Skip to content

[security-audit] FAIL on 2026-06-20 #159

Description

@github-actions

Audit failed at 2026-06-20T05:53Z. Run

Security Audit Report

Audited against SECURITY.md on 2026-06-20.


FAIL IF results

Dependency Supply Chain

# Check Result Evidence
1 node website/scripts/generate-deps.js must not change dependency JSON files FAIL Running the script from a clean checkout modified website/src/data/dependencies-cargo.json (8 insertions, 7 deletions). The base64 0.22.1 crate moved from the transitive section to the direct section (acquiring a declaredName field), indicating a Cargo dependency was promoted to direct without regenerating the supply-chain data. git diff --stat output: website/src/data/dependencies-cargo.json | 15 ++++++++-------
2 package.json must have devEngines.runtime.version as exact MAJOR.MINOR.PATCH PASS package.json:9"version": "22.22.3"
3 standalone/src-tauri/build.rs must verify bundled Node.js matches the pin PASS build.rs:37-38read_pinned_node_version() then verify_node_version() called unconditionally in bundle_node_runtime(). Version mismatch → build error.
4 build-standalone job in release.yml must install the pinned Node from devEngines.runtime.version PASS release.yml:37-51 — reads jq -r '.devEngines.runtime.version', validates MAJOR.MINOR.PATCH regex, passes result to actions/setup-node.
5 pnpm-workspace.yaml must have minimumReleaseAge: 1440 PASS pnpm-workspace.yaml:19minimumReleaseAge: 1440
6 renovate.json must list npm and cargo in enabledManagers PASS renovate.json:3"enabledManagers": ["github-actions", "npm", "cargo"]
7 renovate.json must have minimumReleaseAge package rules for npm/cargo PASS renovate.json:40-53 — three rules: patch=1 day, minor=3 days, major=14 days, each matching matchManagers: ["npm","cargo"]

GitHub Actions Policies

# Check Result Evidence
8 pull_request_target only in tend-*.yaml PASS Only tend-review.yaml uses pull_request_target (line 11). All other workflow files checked: ci.yml, chromatic.yml, release.yml, workflow-audit.yaml, security-audit.yaml — none use pull_request_target.
9 Non-agent-managed workflows must not grant write permissions beyond id-token: write, attestations: write, and actions: write (security-audit job only) PASS ci.yml:9contents: read. chromatic.yml:14contents: read. release.yml top-level contents: read; job-level: build-standalone/build-vscode add id-token: write and attestations: write (provenance); security-audit job adds actions: write; publish-vscode inherits top-level only. All within permitted scope.

Automated Maintainer (tend)

# Check Result Evidence
10 Ruleset "Merge access" must exist, target ~DEFAULT_BRANCH, block only update, and have admin (RepositoryRole actor 5) as sole bypass PASS GH_TOKEN=$AUDIT_PAT gh api repos/$GITHUB_REPOSITORY/rulesets/16757376: target=branch, conditions.ref_name.include=["~DEFAULT_BRANCH"], rules=[{type:"update"}], bypass_actors=[{actor_id:5, actor_type:"RepositoryRole", bypass_mode:"exempt"}]
11 Ruleset "Tag operations" must exist, target ~ALL, block creation and update, have admin-only bypass PASS GH_TOKEN=$AUDIT_PAT gh api repos/$GITHUB_REPOSITORY/rulesets/16757382: target=tag, conditions.ref_name.include=["~ALL"], rules=[{type:"creation"},{type:"update"}], bypass_actors=[{actor_id:5, actor_type:"RepositoryRole", bypass_mode:"exempt"}]
12 dormouse-bot must not hold permission higher than push PASS API response: {"role_name":"write","permissions":{"admin":false,"maintain":false,"push":true,"pull":true,"triage":true}}
13 OVSX_PAT and VSCE_PAT must not appear as repo-level secrets PASS Repo-level secrets listing: CHROMATIC_PROJECT_TOKEN, CLAUDE_CODE_OAUTH_TOKEN, TEND_BOT_TOKEN. Neither OVSX_PAT nor VSCE_PAT present.
14 All environment deployment-branch-policies must admit only admin-gated refs PASS vscode-extension-publish: only v* tags (admin-gated by Tag operations ruleset). security-audit: main branch (admin-gated by Merge access) and v* tags (admin-gated by Tag operations).
15 AUDIT_PAT must be in security-audit environment only, not at repo level PASS security-audit environment secrets: AUDIT_PAT. Repo-level secrets do not include AUDIT_PAT.
16 CHROMATIC_PROJECT_TOKEN must appear in .config/tend.yaml secrets.allowed PASS .config/tend.yaml:5- CHROMATIC_PROJECT_TOKEN
17 workflow-audit.yaml must exist, be enabled, and have a successful run within 48 hours PASS File exists. API: state=active. Last successful run: 2026-06-19T08:54:41Z (~23 hours before this audit).
18 tend-*.yaml workflows must not use unpinned action references (tag pins accepted for tend files) PASS All tend-*.yaml files use actions/checkout@v6 and max-sixty/tend@0.1.6 — both tag-pinned. SECURITY.md explicitly allows tag pins in tend-generated files.
19 Agent-managed workflows must not exceed contents: write, pull-requests: write, issues: write, id-token: write, actions: read, or any read permission PASS All tend-*.yaml files use subsets of exactly those permissions. workflow-audit.yaml: contents: read, issues: write, actions: read. security-audit.yaml: contents: read, actions: read, issues: write, id-token: write.

VS Code Extension Releases

# Check Result Evidence
20 release.yml must include vscode-extension-publish environment on the VS Code publish job PASS release.yml:304-305environment: name: vscode-extension-publish on publish-vscode job
21 VSCE_PAT and OVSX_PAT must only be used within vscode-extension-publish environment PASS release.yml:336VSCE_PAT used only in publish-vscode (which has the vscode-extension-publish environment). release.yml:348OVSX_PAT same. No other workflow file references these secrets.
22 release.yml must not use production desktop signing secrets in CI PASS release.yml generates an ephemeral Tauri updater key (lines 75-87). No macOS signing identity, Windows EV cert, notarization password, or production Tauri private key is referenced anywhere in release.yml.
23 release.yml must generate an ephemeral Tauri updater key for unsigned CI artifacts PASS release.yml:75-87tauri signer generate --ci --write-keys "$key_path" followed by echo "TAURI_SIGNING_PRIVATE_KEY=$key_path" >> "$GITHUB_ENV"

Desktop Releases

# Check Result Evidence
24 sign-and-deploy.sh must verify GitHub artifact attestations PASS sign-and-deploy.sh:393-399gh attestation verify "$manifest" --repo "$GITHUB_REPO" --cert-identity "$identity" --cert-oidc-issuer ... called in verify_downloaded_artifact(), invoked for every artifact before any signing step.
25 sign-and-deploy.sh must verify artifact SHA-256 manifests PASS sign-and-deploy.sh:359-370check_sha256_manifest() using sha256sum -c (or shasum -a 256 -c), called from verify_downloaded_artifact().
26 sign-and-deploy.sh must use PIV-backed Windows signing PASS sign-and-deploy.sh:700-702jsign --storetype PIV --storepass "$EV_SIGN_PIN" --alias "$JSIGN_ALIAS" used for both the executable and the NSIS installer.

CI Validation Contract

# Check Result Evidence
27 security-audit.yaml must exist, be enabled, and be invoked from release.yml's publish path PASS security-audit.yaml exists and gh api confirms state=active. release.yml has a security-audit job that dispatches it, and publish-vscode declares needs: [build-standalone, build-vscode, security-audit].
28 The audit must not be weakened (qualitative pass still required, FAIL IF checks enforceable, failure-reporting step intact, AUDIT_PAT pre-check not removed) PASS security-audit.yaml:49-57 — AUDIT_PAT pre-check present and exits 1 on failure. security-audit.yaml:125-174 — failure-reporting step opens/updates issue labeled security-audit-failure and exits 1 on FAIL. Prompt still requires qualitative pass and mechanical FAIL IF checks.

Qualitative findings

WARNING — Tauri private key exposed in process cmdline (scripts/sign-and-deploy.sh:766)

sign_updates() passes TAURI_SIGNING_PRIVATE_KEY as both an environment variable (correct, Tauri reads it by convention) and a CLI argument (--private-key "$TAURI_SIGNING_PRIVATE_KEY"). On Linux and macOS, process arguments are world-readable via ps aux and /proc/<pid>/cmdline, while environment variables in /proc/<pid>/environ are restricted to the owning user and root. The redundant --private-key argument leaks the private key content to any process or user that runs ps during the brief signing window. The fix is to remove the --private-key CLI flag and rely solely on the TAURI_SIGNING_PRIVATE_KEY env var, which Tauri's signer already reads.

INFO — pnpm install without --frozen-lockfile in non-release workflows

ci.yml (line 35) and chromatic.yml (line 37) run pnpm install without --frozen-lockfile. If the lockfile drifts from the manifests, pnpm will silently update it and install newer package versions than expected. The release workflows (release.yml) correctly use --frozen-lockfile, so release artifacts are not affected. Risk is limited to test/CI correctness rather than shipped software.

INFO — ANTHROPIC_API_KEY not visible in repo or environment secret listings

All tend-*.yaml files reference ${{ secrets.ANTHROPIC_API_KEY }}, but this secret does not appear in the repo-level secret listing (which shows only CHROMATIC_PROJECT_TOKEN, CLAUDE_CODE_OAUTH_TOKEN, TEND_BOT_TOKEN) or in either environment. It is likely an org-level secret. If the org secret is ever removed without adding a repo-level replacement, tend workflows would silently fail their Claude invocations. No SECURITY.md control is violated; this is an operational resilience note.

INFO — workflow-audit.yaml opens a new issue per audit rather than updating a single tracker

Each run of workflow-audit.yaml that finds changes opens a fresh GitHub issue. For repositories with frequent bot activity this can accumulate many open issues. The security-audit.yaml failure loop (update existing issue) is a better pattern. No security boundary is affected.


Summary

FAIL

The audit fails on one FAIL IF violation: running node website/scripts/generate-deps.js from a clean checkout modifies website/src/data/dependencies-cargo.json. The base64 0.22.1 crate has been promoted from a transitive to a direct Cargo dependency (it gained a declaredName field in the direct section), but the supply-chain data file was not regenerated and committed. SECURITY.md requires the generated supply-chain files to be kept in sync with every dependency change, so the disclosed dependency list on the supply-chain page no longer accurately reflects the current Cargo.lock. All other FAIL IF checks pass, and no qualitative findings rise to BLOCKER severity. The one WARNING (Tauri private key in CLI args) is a local-machine risk during the manual signing step and does not affect the CI/release pipeline integrity.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions