You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Audited commit: 81712a7 (main). Repo: diffplug/dormouse. Audit run at 2026-07-13T07:43Z.
FAIL IF results
Dependency Supply Chain
PASS — node website/scripts/generate-deps.js produced no diff against a clean checkout. git status --porcelain and git diff --stat -- website/src/data/dependencies-{npm,cargo,runtime}.json were empty after the script ran (Wrote 26 dependencies..., Wrote 12 direct and 489 transitive Cargo dependencies..., Wrote 1 bundled runtime...).
PASS — package.jsondevEngines.runtime.version = "24.18.0", an exact MAJOR.MINOR.PATCH.
PASS — standalone/src-tauri/build.rs:42-43 calls read_pinned_node_version + verify_node_version before bundling, hard-failing the build on mismatch (build.rs:149-227).
PASS — release.yml:39-41 (build-standalone) uses actions/setup-node@48b55a0... (v6.4.0) with node-version-file: package.json. Verified against upstream actions/setup-node docs at that exact pinned SHA (docs/advanced-usage.md@v6.4.0): node-version-file: package.json resolution order is volta.node → devEngines.runtime (entry named "node") → engines.node; since this repo's package.json has no volta.node, it resolves the pinned devEngines.runtime.version.
PASS — pnpm-workspace.yaml:23 has minimumReleaseAge: 1440.
PASS — .github/renovate.json package rules include minimumReleaseAge for npm/cargo at patch (1 day), minor (3 days), major (14 days) update types.
GitHub Actions Policies
PASS — grep -rln pull_request_target .github/workflows/ returns only .github/workflows/tend-review.yaml.
PASS — Non-agent-managed workflows (ci.yml, chromatic.yml, release.yml) grant only contents: read at the top level (or job-level contents: read). release.yml's build-standalone/build-vscode jobs add only id-token: write + attestations: write; the security-audit job adds only actions: write (release.yml:225-234), matching the documented exception; publish-vscode has no job-level permissions: override and inherits the top-level contents: read.
PASS — Ruleset Tag operations (id 16757382): target: tag, conditions.ref_name.include: ["~ALL"], rules: [{"type":"creation"},{"type":"update"}], same admin-only sole bypass actor.
PASS — GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/collaborators/dormouse-bot/permission → {"permission":"write","permissions":{"admin":false,...,"push":true,...}}. Not higher than push/write.
PASS — GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/actions/secrets → exactly CHROMATIC_PROJECT_TOKEN, CLAUDE_CODE_OAUTH_TOKEN, TEND_BOT_TOKEN. No OVSX_PAT/VSCE_PAT at repo level.
PASS — Environment deployment-branch-policies: vscode-extension-publish → [{"name":"v*","type":"tag"}] only (admin-gated by Tag operations). security-audit → [{"name":"main","type":"branch"},{"name":"v*","type":"tag"}], both admin-gated (Merge access / Tag operations respectively).
PASS — AUDIT_PAT is present in the security-audit environment (gh api .../environments/security-audit/secrets → {"total_count":1,"secrets":[{"name":"AUDIT_PAT",...}]}) and absent from the repo-level secret list (check 13).
PASS — workflow-audit.yamlstate: "active"; latest successful run created_at: 2026-07-12T09:11:11Z, current time 2026-07-13T07:43Z → ~22.5h old, within 48h.
PASS — All 8 tend-*.yaml files pin actions/checkout@v7 and max-sixty/tend/claude@0.1.10 — version-tag pins, which the spec explicitly permits for this file class (none use @main or an unpinned ref).
FAIL — tend-mention.yaml's verify job (lines 34-180) declares no permissions: block at either workflow or job level (only the handle job at line 189 does). The repository's default Actions permission is write: GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/actions/permissions/workflow → {"default_workflow_permissions":"write","can_approve_pull_request_reviews":true} — confirmed live, re-checked twice. This means the job's ambient GITHUB_TOKEN is granted write access to scopes beyond the allowed set (checks, deployments, packages, security-events, statuses, and actions:write rather than the permitted actions:read) — exceeding contents:write, pull-requests:write, issues:write, id-token:write, actions:read, or any read permission. In the current file, every run: step in this job explicitly overrides GITHUB_TOKEN to secrets.TEND_BOT_TOKEN (lines 156, 180), so the ambient elevated token is not exercised by any step today — but the grant itself violates the letter of the rule, and the job is reachable by any GitHub user via issue_comment, pull_request_review, pull_request_review_comment, or an issues: edited event (no collaborator gate on the trigger itself). See qualitative findings for two related issues: the systemic root cause, and evidence that this exact violation has already been reported once and silently regressed.
VS Code Extension Releases
PASS — release.yml:290-291 — publish-vscode job has environment: name: vscode-extension-publish.
PASS — grep -rn "VSCE_PAT\|OVSX_PAT" .github/workflows/ shows both only inside publish-vscode (release.yml:320, 332), which runs under the vscode-extension-publish environment. Confirmed the environment's own secrets store holds exactly OVSX_PAT and VSCE_PAT and neither appears at repo level.
PASS — No production desktop signing secrets (APPLE_SIGN_PASS, EV_SIGN_PIN, non-ephemeral TAURI_SIGNING_PRIVATE_KEY) appear anywhere in release.yml; grep -n "secrets\." release.yml shows only GITHUB_TOKEN, VSCE_PAT, OVSX_PAT.
PASS — release.yml:63-74 ("Generate ephemeral Tauri updater key") runs tauri signer generate --ci --write-keys ... --force and exports it as TAURI_SIGNING_PRIVATE_KEY for the unsigned CI build.
Desktop Releases
PASS — scripts/sign-and-deploy.shverify_downloaded_artifact() (lines 372-404) calls gh attestation verify with --cert-identity/--cert-oidc-issuer/--source-ref/--source-digest, invoked from both download_artifacts_from_run() and the cached-artifact path.
PASS — scripts/sign-and-deploy.shcheck_sha256_manifest() (lines 359-370), called from verify_downloaded_artifact() (line 402), runs sha256sum -c / shasum -a 256 -c against the manifest.
PASS — security-audit.yaml exists, state: "active", and is dispatched from release.yml's security-audit job (release.yml:222-281), which publish-vscode depends on (needs: [build-standalone, build-vscode, security-audit], release.yml:285-288).
PASS — The audit prompt still requires the qualitative pass (security-audit.yaml:90-93), no FAIL IF is marked ignorable, the failure-reporting step that opens/updates a security-audit-failure issue and exit 1s is intact (security-audit.yaml:123-172), and the AUDIT_PAT pre-check (security-audit.yaml:47-55) is present and unbypassed (writes FAIL/error report and exit 1 on a missing secret).
Qualitative findings
BLOCKER — repo-wide default_workflow_permissions is write, not read.GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/actions/permissions/workflow returns {"default_workflow_permissions":"write",...}. This is the root cause of FAIL-IF Improve alert icons (and rename from alarm to alert) #19: any workflow or job — present or future, human-authored or tend-authored — that omits an explicit permissions: block silently receives broad write scopes (contents, issues, pull-requests, checks, deployments, packages, security-events, statuses) instead of the least-privilege default the rest of SECURITY.md's ruleset/environment model assumes. Every other reviewed workflow (ci.yml, chromatic.yml, release.yml, security-audit.yaml, workflow-audit.yaml, and every tend-*.yaml job except tend-mention.yaml's verify) happens to declare an explicit permissions: block, so today's actual exposure is limited to that one job — but the repo setting itself is the hole, not just that job, since it fails open by default for anything added later. Fix: flip the repo setting to read (gh api -X PUT repos/diffplug/dormouse/actions/permissions/workflow -f default_workflow_permissions=read -F can_approve_pull_request_reviews=true, admin-only) and add an explicit least-privilege permissions: block to tend-mention.yaml's verify job.
BLOCKER — the nightly audit has already reported this exact BLOCKER once and silently stopped reporting it without any code change fixing it, undermining the audit's reliability as a release gate. Issue #236 ("[security-audit] FAIL on 2026-07-09") reported this identical finding — same file, same job, same root cause, same evidence — verbatim down to the API response shape. It was auto-closed the next day ("Audit passed at 2026-07-10T07:59Z") by the workflow's own closure logic, which trusts a single subsequent PASS verdict with no diff against the specific prior finding. git log --follow -- .github/workflows/tend-mention.yaml shows the file's only change since 2026-07-01 is the unrelated 0.1.9 → 0.1.10 tend regeneration (de4ef1ff), which did not touch the verify job's permissions; default_workflow_permissions is still write. Yet the workflow runs on 2026-07-10, 2026-07-11, and 2026-07-12 (all conclusion: success, confirmed via gh run list --workflow security-audit.yaml) all passed. Because security-audit.yaml gates the VS Code publish job, a real, unremediated permission-scope gap has been silently waved through four consecutive nightly runs and would not have blocked a release. Recommendation: don't rely solely on the LLM audit's self-reported PASS/FAIL for issue-closure — cross-check that the specific file/finding named in an open security-audit-failure issue was actually touched by an intervening commit before auto-closing, or have the workflow diff the new report against the previous FAIL report before closing.
WARNING — ANTHROPIC_API_KEY is referenced by every tend-*.yaml workflow but is absent from SECURITY.md's threat enumeration and appears unset.grep -rn ANTHROPIC_API_KEY .github/workflows/tend-*.yaml shows it passed as anthropic_api_key: to max-sixty/tend/claude@0.1.10 in all 8 tend workflows, yet SECURITY.md's "Automated Maintainer" section enumerates exactly three reachable secrets (TEND_BOT_TOKEN, CLAUDE_CODE_OAUTH_TOKEN, CHROMATIC_PROJECT_TOKEN). It is not a repo-level secret and does not appear in the org-secrets-visible-to-this-repo list (BUILDCACHE_USER, NEXUS_USER only), so it most likely resolves to an empty string at runtime — no live exposure — but SECURITY.md's tend threat model should either account for it explicitly or the dead reference should be dropped so the documented secret list stays exhaustive.
INFO — targeted scan for hardcoded credentials and unsafe fetch-and-execute patterns found nothing. No ghp_/github_pat_/sk-ant-/AWS-key/PEM-private-key patterns and no curl | sh-style pipelines anywhere in workflows, scripts, or lib/dor source (excluding node_modules/dist).
INFO — no script-injection pattern found in run: blocks. A structural scan of every .github/workflows/*.y*ml file for ${{ github.event.* }}, ${{ github.head_ref }}, or ${{ inputs.* }} interpolated directly inside a run: string (the classic GitHub Actions script-injection vector) found zero matches; every workflow that handles attacker-influenceable text (tend-mention.yaml, tend-triage.yaml, tend-ci-fix.yaml, workflow-audit.yaml) routes it through env: first.
Summary
Overall: FAIL. One concrete FAIL IF violation was confirmed with direct, reproducible evidence: tend-mention.yaml's verify job has no explicit permissions: block and therefore inherits the repository's default_workflow_permissions: write setting, granting it write scopes beyond what SECURITY.md permits for agent-managed workflows. The systemic root cause (the repo-wide default itself) is flagged as its own BLOCKER, and — more seriously — this exact violation was already caught and reported by a prior audit run (issue #236, 2026-07-09) and then silently stopped being reported for three consecutive nightly runs despite no code change remediating it, which is flagged as a second BLOCKER because it means the audit's PASS verdict cannot currently be trusted as proof that a previously-identified gap was fixed. All 27 other FAIL IF checks passed with direct evidence, and no hardcoded secrets, unsafe curl | sh patterns, or script-injection vectors were found in the qualitative pass. Remediation is narrow: set the repo's default workflow permission to read and add an explicit least-privilege permissions: block to tend-mention.yaml's verify job (patch upstream in the tend generator, or expect a manual override to be reverted on next regeneration), and harden the audit's auto-close logic so a stale PASS run can't silently supersede an unfixed FAIL.
Audit failed at 2026-07-13T07:51Z. Run
Security Audit Report
Audited commit:
81712a7(main). Repo:diffplug/dormouse. Audit run at 2026-07-13T07:43Z.FAIL IF results
Dependency Supply Chain
node website/scripts/generate-deps.jsproduced no diff against a clean checkout.git status --porcelainandgit diff --stat -- website/src/data/dependencies-{npm,cargo,runtime}.jsonwere empty after the script ran (Wrote 26 dependencies...,Wrote 12 direct and 489 transitive Cargo dependencies...,Wrote 1 bundled runtime...).package.jsondevEngines.runtime.version="24.18.0", an exactMAJOR.MINOR.PATCH.standalone/src-tauri/build.rs:42-43callsread_pinned_node_version+verify_node_versionbefore bundling, hard-failing the build on mismatch (build.rs:149-227).release.yml:39-41(build-standalone) usesactions/setup-node@48b55a0...(v6.4.0) withnode-version-file: package.json. Verified against upstreamactions/setup-nodedocs at that exact pinned SHA (docs/advanced-usage.md@v6.4.0):node-version-file: package.jsonresolution order isvolta.node→devEngines.runtime(entry named"node") →engines.node; since this repo'spackage.jsonhas novolta.node, it resolves the pinneddevEngines.runtime.version.pnpm-workspace.yaml:23hasminimumReleaseAge: 1440..github/renovate.jsonenabledManagers:["github-actions", "npm", "cargo"]..github/renovate.jsonpackage rules includeminimumReleaseAgefornpm/cargoatpatch(1 day),minor(3 days),major(14 days) update types.GitHub Actions Policies
grep -rln pull_request_target .github/workflows/returns only.github/workflows/tend-review.yaml.ci.yml,chromatic.yml,release.yml) grant onlycontents: readat the top level (or job-levelcontents: read).release.yml'sbuild-standalone/build-vscodejobs add onlyid-token: write+attestations: write; thesecurity-auditjob adds onlyactions: write(release.yml:225-234), matching the documented exception;publish-vscodehas no job-levelpermissions:override and inherits the top-levelcontents: read.Automated Maintainer (tend)
Merge access(id16757376):target: branch,conditions.ref_name.include: ["~DEFAULT_BRANCH"],rules: [{"type":"update"}]only,bypass_actors: [{"actor_id":5,"actor_type":"RepositoryRole","bypass_mode":"exempt"}](role 5 = Admin), sole bypass actor.Tag operations(id16757382):target: tag,conditions.ref_name.include: ["~ALL"],rules: [{"type":"creation"},{"type":"update"}], same admin-only sole bypass actor.GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/collaborators/dormouse-bot/permission→{"permission":"write","permissions":{"admin":false,...,"push":true,...}}. Not higher than push/write.GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/actions/secrets→ exactlyCHROMATIC_PROJECT_TOKEN,CLAUDE_CODE_OAUTH_TOKEN,TEND_BOT_TOKEN. NoOVSX_PAT/VSCE_PATat repo level.vscode-extension-publish→[{"name":"v*","type":"tag"}]only (admin-gated byTag operations).security-audit→[{"name":"main","type":"branch"},{"name":"v*","type":"tag"}], both admin-gated (Merge access/Tag operationsrespectively).AUDIT_PATis present in thesecurity-auditenvironment (gh api .../environments/security-audit/secrets→{"total_count":1,"secrets":[{"name":"AUDIT_PAT",...}]}) and absent from the repo-level secret list (check 13)..config/tend.yaml:4-5—secrets: allowed: [CHROMATIC_PROJECT_TOKEN].workflow-audit.yamlstate: "active"; latest successful runcreated_at: 2026-07-12T09:11:11Z, current time2026-07-13T07:43Z→ ~22.5h old, within 48h.tend-*.yamlfiles pinactions/checkout@v7andmax-sixty/tend/claude@0.1.10— version-tag pins, which the spec explicitly permits for this file class (none use@mainor an unpinned ref).tend-mention.yaml'sverifyjob (lines 34-180) declares nopermissions:block at either workflow or job level (only thehandlejob at line 189 does). The repository's default Actions permission iswrite:GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/actions/permissions/workflow→{"default_workflow_permissions":"write","can_approve_pull_request_reviews":true}— confirmed live, re-checked twice. This means the job's ambientGITHUB_TOKENis granted write access to scopes beyond the allowed set (checks,deployments,packages,security-events,statuses, andactions:writerather than the permittedactions:read) — exceedingcontents:write, pull-requests:write, issues:write, id-token:write, actions:read, or any read permission. In the current file, everyrun:step in this job explicitly overridesGITHUB_TOKENtosecrets.TEND_BOT_TOKEN(lines 156, 180), so the ambient elevated token is not exercised by any step today — but the grant itself violates the letter of the rule, and the job is reachable by any GitHub user viaissue_comment,pull_request_review,pull_request_review_comment, or anissues: editedevent (no collaborator gate on the trigger itself). See qualitative findings for two related issues: the systemic root cause, and evidence that this exact violation has already been reported once and silently regressed.VS Code Extension Releases
release.yml:290-291—publish-vscodejob hasenvironment: name: vscode-extension-publish.grep -rn "VSCE_PAT\|OVSX_PAT" .github/workflows/shows both only insidepublish-vscode(release.yml:320, 332), which runs under thevscode-extension-publishenvironment. Confirmed the environment's own secrets store holds exactlyOVSX_PATandVSCE_PATand neither appears at repo level.APPLE_SIGN_PASS,EV_SIGN_PIN, non-ephemeralTAURI_SIGNING_PRIVATE_KEY) appear anywhere inrelease.yml;grep -n "secrets\." release.ymlshows onlyGITHUB_TOKEN,VSCE_PAT,OVSX_PAT.release.yml:63-74("Generate ephemeral Tauri updater key") runstauri signer generate --ci --write-keys ... --forceand exports it asTAURI_SIGNING_PRIVATE_KEYfor the unsigned CI build.Desktop Releases
scripts/sign-and-deploy.shverify_downloaded_artifact()(lines 372-404) callsgh attestation verifywith--cert-identity/--cert-oidc-issuer/--source-ref/--source-digest, invoked from bothdownload_artifacts_from_run()and the cached-artifact path.scripts/sign-and-deploy.shcheck_sha256_manifest()(lines 359-370), called fromverify_downloaded_artifact()(line 402), runssha256sum -c/shasum -a 256 -cagainst the manifest.scripts/sign-and-deploy.shsign_windows()(lines 683-718) usesjsign --storetype PIV --storepass "$EV_SIGN_PIN" --alias "$JSIGN_ALIAS" ....CI Validation Contract
security-audit.yamlexists,state: "active", and is dispatched fromrelease.yml'ssecurity-auditjob (release.yml:222-281), whichpublish-vscodedepends on (needs: [build-standalone, build-vscode, security-audit],release.yml:285-288).security-audit.yaml:90-93), noFAIL IFis marked ignorable, the failure-reporting step that opens/updates asecurity-audit-failureissue andexit 1s is intact (security-audit.yaml:123-172), and theAUDIT_PATpre-check (security-audit.yaml:47-55) is present and unbypassed (writesFAIL/error report andexit 1on a missing secret).Qualitative findings
BLOCKER — repo-wide
default_workflow_permissionsiswrite, notread.GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/actions/permissions/workflowreturns{"default_workflow_permissions":"write",...}. This is the root cause of FAIL-IF Improve alert icons (and rename from alarm to alert) #19: any workflow or job — present or future, human-authored ortend-authored — that omits an explicitpermissions:block silently receives broad write scopes (contents,issues,pull-requests,checks,deployments,packages,security-events,statuses) instead of the least-privilege default the rest of SECURITY.md's ruleset/environment model assumes. Every other reviewed workflow (ci.yml,chromatic.yml,release.yml,security-audit.yaml,workflow-audit.yaml, and everytend-*.yamljob excepttend-mention.yaml'sverify) happens to declare an explicitpermissions:block, so today's actual exposure is limited to that one job — but the repo setting itself is the hole, not just that job, since it fails open by default for anything added later. Fix: flip the repo setting toread(gh api -X PUT repos/diffplug/dormouse/actions/permissions/workflow -f default_workflow_permissions=read -F can_approve_pull_request_reviews=true, admin-only) and add an explicit least-privilegepermissions:block totend-mention.yaml'sverifyjob.BLOCKER — the nightly audit has already reported this exact BLOCKER once and silently stopped reporting it without any code change fixing it, undermining the audit's reliability as a release gate. Issue #236 ("[security-audit] FAIL on 2026-07-09") reported this identical finding — same file, same job, same root cause, same evidence — verbatim down to the API response shape. It was auto-closed the next day ("Audit passed at 2026-07-10T07:59Z") by the workflow's own closure logic, which trusts a single subsequent PASS verdict with no diff against the specific prior finding.
git log --follow -- .github/workflows/tend-mention.yamlshows the file's only change since 2026-07-01 is the unrelated0.1.9 → 0.1.10tend regeneration (de4ef1ff), which did not touch theverifyjob's permissions;default_workflow_permissionsis stillwrite. Yet the workflow runs on 2026-07-10, 2026-07-11, and 2026-07-12 (allconclusion: success, confirmed viagh run list --workflow security-audit.yaml) all passed. Becausesecurity-audit.yamlgates the VS Code publish job, a real, unremediated permission-scope gap has been silently waved through four consecutive nightly runs and would not have blocked a release. Recommendation: don't rely solely on the LLM audit's self-reported PASS/FAIL for issue-closure — cross-check that the specific file/finding named in an opensecurity-audit-failureissue was actually touched by an intervening commit before auto-closing, or have the workflow diff the new report against the previous FAIL report before closing.WARNING —
ANTHROPIC_API_KEYis referenced by everytend-*.yamlworkflow but is absent from SECURITY.md's threat enumeration and appears unset.grep -rn ANTHROPIC_API_KEY .github/workflows/tend-*.yamlshows it passed asanthropic_api_key:tomax-sixty/tend/claude@0.1.10in all 8 tend workflows, yet SECURITY.md's "Automated Maintainer" section enumerates exactly three reachable secrets (TEND_BOT_TOKEN,CLAUDE_CODE_OAUTH_TOKEN,CHROMATIC_PROJECT_TOKEN). It is not a repo-level secret and does not appear in the org-secrets-visible-to-this-repo list (BUILDCACHE_USER,NEXUS_USERonly), so it most likely resolves to an empty string at runtime — no live exposure — but SECURITY.md's tend threat model should either account for it explicitly or the dead reference should be dropped so the documented secret list stays exhaustive.INFO — targeted scan for hardcoded credentials and unsafe fetch-and-execute patterns found nothing. No
ghp_/github_pat_/sk-ant-/AWS-key/PEM-private-key patterns and nocurl | sh-style pipelines anywhere in workflows, scripts, or lib/dor source (excludingnode_modules/dist).INFO — no script-injection pattern found in
run:blocks. A structural scan of every.github/workflows/*.y*mlfile for${{ github.event.* }},${{ github.head_ref }}, or${{ inputs.* }}interpolated directly inside arun:string (the classic GitHub Actions script-injection vector) found zero matches; every workflow that handles attacker-influenceable text (tend-mention.yaml,tend-triage.yaml,tend-ci-fix.yaml,workflow-audit.yaml) routes it throughenv:first.Summary
Overall: FAIL. One concrete
FAIL IFviolation was confirmed with direct, reproducible evidence:tend-mention.yaml'sverifyjob has no explicitpermissions:block and therefore inherits the repository'sdefault_workflow_permissions: writesetting, granting it write scopes beyond what SECURITY.md permits for agent-managed workflows. The systemic root cause (the repo-wide default itself) is flagged as its own BLOCKER, and — more seriously — this exact violation was already caught and reported by a prior audit run (issue #236, 2026-07-09) and then silently stopped being reported for three consecutive nightly runs despite no code change remediating it, which is flagged as a second BLOCKER because it means the audit's PASS verdict cannot currently be trusted as proof that a previously-identified gap was fixed. All 27 otherFAIL IFchecks passed with direct evidence, and no hardcoded secrets, unsafecurl | shpatterns, or script-injection vectors were found in the qualitative pass. Remediation is narrow: set the repo's default workflow permission toreadand add an explicit least-privilegepermissions:block totend-mention.yaml'sverifyjob (patch upstream in thetendgenerator, or expect a manual override to be reverted on next regeneration), and harden the audit's auto-close logic so a stale PASS run can't silently supersede an unfixed FAIL.