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
PASS — node website/scripts/generate-deps.js produced no diff against a clean checkout. Ran it directly: git status --porcelain and git diff --stat were empty after the script wrote Wrote 26 dependencies..., Wrote 12 direct and 489 transitive Cargo dependencies..., Wrote 1 bundled runtime....
PASS — package.json:6-11 has devEngines.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, failing the build on mismatch (build.rs:149-215).
PASS — release.yml:39-41 (build-standalone) uses actions/setup-node@...v6.4.0 with node-version-file: package.json, which resolves devEngines.runtime.version per the workflow's own comment (release.yml:34-38). Indirect confirmation: recent CI runs (which run the same cargo check / node-version-file path in standalone-smoketest) are green (gh api .../actions/workflows/ci.yml/runs → 3/3 latest conclusion: success), which would be impossible if the pin resolution were broken, since build.rs hard-fails on mismatch.
PASS — pnpm-workspace.yaml:18 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 -rn pull_request_target .github/workflows/ returns only .github/workflows/tend-review.yaml:11.
PASS — Non-agent-managed workflows (ci.yml, chromatic.yml, release.yml) grant only contents: read at the top level; release.yml's build-standalone/build-vscode jobs add only id-token: write + attestations: write (release.yml:14-17, 157-160); the security-audit job adds only actions: write (release.yml:225-234), matching the documented exception. publish-vscode has no job-level permissions: override, so it 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", ...}. Not higher than push/write.
PASS — GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/actions/secrets → only 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).
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's output).
PASS — workflow-audit.yamlstate: "active"; latest successful run created_at: 2026-07-08T09:32:13Z, current time 2026-07-09T07:56:30Z → ~22.4h old, within 48h.
PASS — All 8 tend-*.yaml files pin actions/checkout@v7 and max-sixty/tend/claude@0.1.9 — 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 33-165) declares no permissions: block at either workflow or job level (only the handle job at line 169 does). The repo's default Actions permission is write (GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/actions/permissions/workflow → {"default_workflow_permissions":"write", ...}), which grants the job's ambient GITHUB_TOKEN write access to scopes beyond the allowed set (e.g. checks, deployments, packages, security-events, statuses write) — exceeding contents:write, pull-requests:write, issues:write, id-token:write, actions:read, read-*. In practice every gh api call in this job explicitly overrides GITHUB_TOKEN to secrets.TEND_BOT_TOKEN (lines 138, 160), so the ambient elevated token is not currently exercised — but the grant itself violates the letter of the rule. See qualitative findings for the root cause.
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.
PASS — No production desktop signing secrets (APPLE_SIGN_PASS, EV_SIGN_PIN, non-ephemeral TAURI_SIGNING_PRIVATE_KEY) appear anywhere in release.yml; the only Tauri key material in CI is the ephemeral one generated at release.yml:63-74.
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.sh:392-399 (verify_downloaded_artifact) calls gh attestation verify with --cert-identity/--cert-oidc-issuer/--source-ref/--source-digest.
PASS — scripts/sign-and-deploy.sh:359-370, 402 (check_sha256_manifest) runs sha256sum -c / shasum -a 256 -c against the manifest.
PASS — security-audit.yaml exists, state: "active" (checked via gh api .../actions/workflows/security-audit.yaml), and is dispatched from release.yml's security-audit job (release.yml:236-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: "Then do a qualitative pass over..."), 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 (exit 1 on 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","can_approve_pull_request_reviews":true}. 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) rather than the least-privilege default the rest of SECURITY.md's ruleset/environment model is built around. Every currently-reviewed non-agent-managed workflow (ci.yml, chromatic.yml, release.yml) happens to declare an explicit top-level permissions: contents: read, so today's actual exposure is limited to the one tend-mention.yaml job identified above — but the repo setting itself is the hole, not just that one job. Recommended fix: flip the org/repo setting to read and add an explicit permissions: block to every job (including tend-mention.yaml's verify job) that needs anything more.
WARNING — ANTHROPIC_API_KEY is referenced by every tend-*.yaml workflow but is absent from SECURITY.md's threat enumeration.grep -rn ANTHROPIC_API_KEY .github/workflows/ shows it passed as anthropic_api_key: to max-sixty/tend/claude@0.1.9 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) as the complete accepted blast radius. It is not a repo-level secret (confirmed via check Themes for standalone and web playground #13's listing), so if it resolves to a real value it must be an org-level secret — org-secret listing (gh api orgs/diffplug/actions/secrets) returned 403 Resource not accessible by personal access token under AUDIT_PAT, which is expected and not a scope drift (SECURITY.md only provisions AUDIT_PAT with repo-scoped Administration/Secrets/Environments, never org-level access) but does make this UNVERIFIABLE whether the secret is populated or dead. Either way, SECURITY.md's tend threat model should be updated to account for it, or the reference should be removed if unused.
INFO — qualitative code-level scan (spawn/subprocess/crypto/auth) found nothing. A targeted review of dor-lib-common/ (spawnAndCapture uses cross-spawn with an argument array, no shell: true, no string interpolation), server-lib-common/src/security/ (randomness via crypto.getRandomValues/randomBytes, timing-safe comparisons throughout, correct passkey/ACL verification order, key hash checked against stored ACL value rather than trusting the wire), and server/src/ (session/bearer gating before WS upgrade, no user-controlled path reaching static file serving) turned up no exploitable issues. No hardcoded credentials (ghp_, github_pat_, sk-ant-, AWS keys, PEM private keys) or curl | sh-style patterns were found anywhere in the tree.
Summary
Overall: FAIL. One concrete FAIL IF violation (#19) was confirmed: the verify job in tend-mention.yaml 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. That repo-level default itself is flagged BLOCKER in the qualitative section as the systemic root cause — it is a live gap in the least-privilege model the rest of the document (rulesets, environment scoping, per-workflow permission caps) is built to enforce, even though no currently-reviewed workflow exploits it beyond the one job. All 27 other FAIL IF checks passed with direct evidence, and the deeper qualitative code scan (subprocess spawning, crypto/auth primitives, server request handling, hardcoded-secret patterns) found no additional vulnerabilities. Remediation is narrow and low-risk: set the repo's default workflow permission to read and add an explicit least-privilege permissions: block to the tend-mention.yamlverify job (and, since it's a tend-generated file, either patch it upstream in the tend generator or accept the override will be reverted on next regeneration).
Audit failed at 2026-07-09T08:03Z. Run
Security Audit Report
Audited commit:
05bb639(main). Repo:diffplug/dormouse.FAIL IF results
Dependency Supply Chain
node website/scripts/generate-deps.jsproduced no diff against a clean checkout. Ran it directly:git status --porcelainandgit diff --statwere empty after the script wroteWrote 26 dependencies...,Wrote 12 direct and 489 transitive Cargo dependencies...,Wrote 1 bundled runtime....package.json:6-11hasdevEngines.runtime.version: "24.18.0", an exactMAJOR.MINOR.PATCH.standalone/src-tauri/build.rs:42-43callsread_pinned_node_version+verify_node_versionbefore bundling, failing the build on mismatch (build.rs:149-215).release.yml:39-41(build-standalone) usesactions/setup-node@...v6.4.0withnode-version-file: package.json, which resolvesdevEngines.runtime.versionper the workflow's own comment (release.yml:34-38). Indirect confirmation: recentCIruns (which run the samecargo check/ node-version-file path instandalone-smoketest) are green (gh api .../actions/workflows/ci.yml/runs→ 3/3 latestconclusion: success), which would be impossible if the pin resolution were broken, sincebuild.rshard-fails on mismatch.pnpm-workspace.yaml:18hasminimumReleaseAge: 1440..github/renovate.json:3—"enabledManagers": ["github-actions", "npm", "cargo"]..github/renovate.jsonpackage rules includeminimumReleaseAgefornpm/cargoatpatch(1 day),minor(3 days),major(14 days) update types.GitHub Actions Policies
grep -rn pull_request_target .github/workflows/returns only.github/workflows/tend-review.yaml:11.ci.yml,chromatic.yml,release.yml) grant onlycontents: readat the top level;release.yml'sbuild-standalone/build-vscodejobs add onlyid-token: write+attestations: write(release.yml:14-17,157-160); thesecurity-auditjob adds onlyactions: write(release.yml:225-234), matching the documented exception.publish-vscodehas no job-levelpermissions:override, so it 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", ...}. Not higher than push/write.GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/actions/secrets→ onlyCHROMATIC_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 by Tag operations).security-audit→[{"name":"main","type":"branch"},{"name":"v*","type":"tag"}], both admin-gated (Merge access / Tag operations).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's output)..config/tend.yaml:4-5—secrets: allowed: [CHROMATIC_PROJECT_TOKEN].workflow-audit.yamlstate: "active"; latest successful runcreated_at: 2026-07-08T09:32:13Z, current time2026-07-09T07:56:30Z→ ~22.4h old, within 48h.tend-*.yamlfiles pinactions/checkout@v7andmax-sixty/tend/claude@0.1.9— version-tag pins, which the spec explicitly permits for this file class (none use@mainor an unpinned ref).tend-mention.yaml'sverifyjob (lines 33-165) declares nopermissions:block at either workflow or job level (only thehandlejob at line 169 does). The repo's default Actions permission iswrite(GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/actions/permissions/workflow→{"default_workflow_permissions":"write", ...}), which grants the job's ambientGITHUB_TOKENwrite access to scopes beyond the allowed set (e.g.checks,deployments,packages,security-events,statuseswrite) — exceedingcontents:write, pull-requests:write, issues:write, id-token:write, actions:read, read-*. In practice everygh apicall in this job explicitly overridesGITHUB_TOKENtosecrets.TEND_BOT_TOKEN(lines 138, 160), so the ambient elevated token is not currently exercised — but the grant itself violates the letter of the rule. See qualitative findings for the root cause.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.APPLE_SIGN_PASS,EV_SIGN_PIN, non-ephemeralTAURI_SIGNING_PRIVATE_KEY) appear anywhere inrelease.yml; the only Tauri key material in CI is the ephemeral one generated atrelease.yml:63-74.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.sh:392-399(verify_downloaded_artifact) callsgh attestation verifywith--cert-identity/--cert-oidc-issuer/--source-ref/--source-digest.scripts/sign-and-deploy.sh:359-370, 402(check_sha256_manifest) runssha256sum -c/shasum -a 256 -cagainst the manifest.scripts/sign-and-deploy.sh:695-714(sign_windows) usesjsign --storetype PIV ....CI Validation Contract
security-audit.yamlexists,state: "active"(checked viagh api .../actions/workflows/security-audit.yaml), and is dispatched fromrelease.yml'ssecurity-auditjob (release.yml:236-281), whichpublish-vscodedepends on (needs: [build-standalone, build-vscode, security-audit],release.yml:285-288).security-audit.yaml:90-93: "Then do a qualitative pass over..."), 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 (exit 1on missing secret).Qualitative findings
default_workflow_permissionsiswrite, notread.GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/actions/permissions/workflowreturns{"default_workflow_permissions":"write","can_approve_pull_request_reviews":true}. 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) rather than the least-privilege default the rest of SECURITY.md's ruleset/environment model is built around. Every currently-reviewed non-agent-managed workflow (ci.yml,chromatic.yml,release.yml) happens to declare an explicit top-levelpermissions: contents: read, so today's actual exposure is limited to the onetend-mention.yamljob identified above — but the repo setting itself is the hole, not just that one job. Recommended fix: flip the org/repo setting toreadand add an explicitpermissions:block to every job (includingtend-mention.yaml'sverifyjob) that needs anything more.ANTHROPIC_API_KEYis referenced by everytend-*.yamlworkflow but is absent from SECURITY.md's threat enumeration.grep -rn ANTHROPIC_API_KEY .github/workflows/shows it passed asanthropic_api_key:tomax-sixty/tend/claude@0.1.9in 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) as the complete accepted blast radius. It is not a repo-level secret (confirmed via check Themes for standalone and web playground #13's listing), so if it resolves to a real value it must be an org-level secret — org-secret listing (gh api orgs/diffplug/actions/secrets) returned403 Resource not accessible by personal access tokenunderAUDIT_PAT, which is expected and not a scope drift (SECURITY.md only provisionsAUDIT_PATwith repo-scoped Administration/Secrets/Environments, never org-level access) but does make this UNVERIFIABLE whether the secret is populated or dead. Either way, SECURITY.md's tend threat model should be updated to account for it, or the reference should be removed if unused.dor-lib-common/(spawnAndCaptureusescross-spawnwith an argument array, noshell: true, no string interpolation),server-lib-common/src/security/(randomness viacrypto.getRandomValues/randomBytes, timing-safe comparisons throughout, correct passkey/ACL verification order, key hash checked against stored ACL value rather than trusting the wire), andserver/src/(session/bearer gating before WS upgrade, no user-controlled path reaching static file serving) turned up no exploitable issues. No hardcoded credentials (ghp_,github_pat_,sk-ant-, AWS keys, PEM private keys) orcurl | sh-style patterns were found anywhere in the tree.Summary
Overall: FAIL. One concrete
FAIL IFviolation (#19) was confirmed: theverifyjob intend-mention.yamlhas 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. That repo-level default itself is flagged BLOCKER in the qualitative section as the systemic root cause — it is a live gap in the least-privilege model the rest of the document (rulesets, environment scoping, per-workflow permission caps) is built to enforce, even though no currently-reviewed workflow exploits it beyond the one job. All 27 otherFAIL IFchecks passed with direct evidence, and the deeper qualitative code scan (subprocess spawning, crypto/auth primitives, server request handling, hardcoded-secret patterns) found no additional vulnerabilities. Remediation is narrow and low-risk: set the repo's default workflow permission toreadand add an explicit least-privilegepermissions:block to thetend-mention.yamlverifyjob (and, since it's atend-generated file, either patch it upstream in thetendgenerator or accept the override will be reverted on next regeneration).