[security-audit] FAIL on 2026-10-03
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Idoneità per principianti
- 35/100
- Tipo di issue
- Bug
- Chiarezza
- Da chiarire
- Stato di attività
- Attiva
- Stack tecnologico
- node.js, typescript
- Ambito
- documentation, security, testing
Direzione di ricerca
Start with the failing audit-application.md section and its linked run transcript, then inspect scripts/loopback-lint.mjs, scripts/loopback-lint-selftest.mjs, scripts/e2e-lint.mjs, and the referenced security and CLI specs. Re-run the security audit and its available lint or test commands; done means the reported FAIL and associated warnings are resolved and the audit passes.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Audit failed at 2026-10-02T10:37Z. Run · Transcript
- A domain returned
FAIL. audit-application.md opened withVERDICT: FAIL— read that domain's section first. A domain's own verdict outranks the merged one.
Lines that decided this verdict
Lifted out of the fragments so truncation cannot cut them. Each domain's full section follows for as far as the body reaches.
audit-supply-chain.md: VERDICT: PASSaudit-ci-secrets.md: VERDICT: PASSaudit-application.md: VERDICT: FAILaudit-hosted.md: VERDICT: PASSaudit-application.md: - WARNING: scripts/loopback-lint.mjs checks 2 (stale ALLOWED entry, :205-213) and 3 (zero non-test listeners matched, :216-222) have no self-test case — scripts/loopback-lint-selftest.mjs only plants bind-form, .mts-extension, and test-file fixtures; AGENTS.md says a lint rule without its self-test case "is not enforced". Code side is behind: add mutations (e.g. a bogus ALLOWED path; a LISTEN_RE that matches nothing).audit-application.md: - FAIL: docs/specs/security-remote.md#Trust boundary — each rule names a line in security-remote.md or security-hosted.md -> "Rendezvous boundary" — evidence: two rules ('Hosted's RelayRoom never names, parses, decodes, logs, or stores a frame', 'The shared frame layer copiesctfield by field and reads it nowhere', scripts/e2e-lint.mjs:476,489) cite docs/specs/security-hosted.md:62 under '## Relay boundary', not 'Rendezvous boundary'. Spec side is wrong (the FAIL IF text is stale; AGENTS.audit-application.md: - WARNING: docs/specs/security-remote.md#Trust boundary (e2e-lint FAIL IF) says each rule names a line in security-remote.md or security-hosted.md -> "Rendezvous boundary"; two RULES (scripts/e2e-lint.mjs:476,489) cite security-hosted.md '## Relay boundary' (line 62). Spec text is stale; update it to name both hosted headings.audit-application.md: - UNVERIFIABLE: security-remote.md#Credentials at rest / setup password — relay unit tests (config, setup-password-store, token-bucket, burrows, cors) not executed — reason: relay/dist not built in this checkout (node --test failed at import); verdicts above are from source readingaudit-application.md: - WARNING: One-time phone page keeps-nothing rule is only textual: the shipped /connect/ bundle (built with lib/vite.one-time.config.ts to /tmp/ot-dist) contains lib/src/lib/local-json-store.ts readers/writers pulled in transitively (alert-settings.ts, watched-commands.ts, session-activity-store.ts, alert-manager.ts, and even lib/src/lib/platform/vscode-adapter.ts via PocketWall/remote-wall/terminal-registry); the minified bundle runs localStorage.getItem('dormouse:alert-settings') at module iniaudit-application.md: - WARNING: Spec drift / inconsistent hardening on bare-name spawns:lib/src/host/git-cli.ts:14callsspawnAndCapture('git', ...)with the bare name, which cross-spawn resolves throughwhich— searching the cwd before PATH on Windows. That is the exact hazarddocs/specs/dor-cli.md-> "Spawning External Binaries" (lines 107-122) names, yet that rule lists onlydor agent-browser,dor playwrightand the browser hosts.dor-tools-builtin/src/folder-viewer.ts:54already resolves git viaaudit-application.md: - WARNING: security-remote.md#Trust boundary: the e2e-lint FAIL IF is violated as written. TwoRULESentries, atscripts/e2e-lint.mjs:476and:489, citedocs/specs/security-hosted.md-> "Relay boundary" (line 44). The FAIL IF (docs/specs/security-remote.md:61) allows only "Rendezvous boundary". The spec text is the stale side: it should name both headings, as the lint header (scripts/e2e-lint.mjs:6) already does. Both rules are enforced and self-tested.audit-application.md: - WARNING:scripts/loopback-lint.mjshas two checks with no self-test case: the stale-allowlist check (:205-213) and the zero-listeners check (:216-222). By the AGENTS.md rule they are not enforced. Fix the code side.audit-application.md: - WARNING: The one-time phone bundle pulls inlocal-json-storereaders and writers transitively (alert-settings and others). The "keeps nothing" rule is checked only by text, on a narrow file set. Either add a bundle-level assert or narrow the spec.audit-application.md: - WARNING:lib/src/host/git-cli.ts:14spawnsgitby its bare name. On Windows that searches the current directory before PATH.docs/specs/dor-cli.md-> "Spawning External Binaries" covers only the browser tools. Not attacker-reachable today.audit-hosted.md: - WARNING: Bearer-gated relay routes reach Postgres without a per-address limit.requireSession/requireBurrow/readAsBurrowcheck only the bearer's shape (isRelayBearer) before aSELECT ... WHERE "tokenHash" = $1(hosted/server/relay-auth.ts:142-153). Anyone can make up a 32-byte base64url bearer and send unlimited requests toGET /api/burrows,POST /api/burrow/setup-token,reauth/*,setup/retireand the push routes; each costs one connection and one indexed read. Nothing confid
Security audit
Supply chain
VERDICT: PASS
FAIL IF results
- PASS: generate-deps.js against clean tree after install produced no diff in website/src/data/ (git status clean; 70 npm, 12 direct + 478 transitive cargo, 1 runtime).
- PASS: .github/workflows/ci.yml lines 24-46 run
pnpm install --frozen-lockfilethennode website/scripts/generate-deps.jsandexit 1ongit diff --quiet -- website/src/data/. - PASS: roots (generate-deps.js:23-30) = dor, dormouse, dormouse-standalone, dormouse-lib, dormouse-sidecar, relay; exclusions (line 33) = canopy, dormouse-website, dormouse-hosted. All 13 pnpm-workspace.yaml packages classified; remote-lib-common, dor-lib-common, dor-tools-builtin, dor-tools-lib are link: edges from roots (pnpm-lock.yaml). Tauri resources only "../sidecar/**/*"; no excluded package is a dependency of a root.
- PASS: package.json devEngines.runtime.version is exactly 24.18.0.
- PASS: standalone/src-tauri/build.rs:43 calls verify_node_version, which runs
--versionand errors on mismatch (lines 207-224); only skip is host != target (line 197), and release.yml standalone matrix (lines 28-36) is all host-native (ubuntu x86_64, macos aarch64, windows x86_64). - PASS: release.yml build-standalone uses setup-node with node-version-file: package.json (lines 47-49); root package.json has no volta or engines.node field.
- PASS: pnpm-workspace.yaml has minimumReleaseAge: 1440.
- PASS: minimumReleaseAgeExclude is only pgstencil and @pgstencil/*; Renovate's only null minimumReleaseAge rule is the pgstencil / @pgstencil/** rule.
- PASS: renovate.json enabledManagers includes npm and cargo; packageRules set minimumReleaseAge for npm+cargo (patch 1 day, minor 3 days, major 14 days).
- PASS: renovate.json vulnerabilityAlerts block sets minimumReleaseAge "1 day" explicitly.
- PASS: secret_scanning enabled and secret_scanning_push_protection enabled (AUDIT_PAT read); vulnerability-alerts returned 204.
Qualitative findings
- INFO: only lockfile entry outside the npm registry is @diffplug/xterm-addon-webgl-sdf (GitHub release tarball with integrity hash), imported by canopy only, which is an excluded Storybook-only workspace. node@runtime:24.18.0 is the pinned runtime, with integrity.
- INFO: install-script packages are governed by allowBuilds in pnpm-workspace.yaml (node-pty, esbuild, sharp, workerd, @swc/core enabled); node-pty is shipped and disclosed. No undisclosed shipped package found.
- INFO: dependabot_security_updates is disabled; the spec only requires alerts, so not a violation.
- INFO: no newly added runtime dependency since the last audit could be identified from a diff; the disclosure snapshot is current.
CI and secrets
VERDICT: PASS
FAIL IF results
- PASS security.md PVR enabled: API
{"enabled":true}. - PASS security-ci pull_request_target not in non-tend workflows: only a comment at hosted-preview.yml:76.
- PASS non-agent workflows effective write perms: argos/ci/hosted-*/release default
contents: read; release.yml build jobs add only id-token/attestations write (lines 21-24,184-187); security-audit jobactions: write(line 252-259). Repo default permsread. - PASS agent-managed workflows effective perms: tend-* jobs only contents/pull-requests/issues write + actions read; security-audit.yaml and workflow-audit.yaml workflow-level only contents/issues/id-token/actions/pull-requests (read where applicable); no job-level overrides.
- PASS action SHA pinning in non-tend workflows: grep for
uses:lacking 40-hex SHA found none. - PASS tend-* pins: all
actions/checkout@v7,[email protected],max-sixty/tend/[email protected](tag pins, none unpinned); 0.3.5 >= 0.1.19. - PASS Merge access ruleset (16757376): ~DEFAULT_BRANCH, rules exactly update/deletion/creation, sole bypass RepositoryRole 5, active.
- PASS Tag operations ruleset (16757382): ~ALL tags, rules creation+update, sole bypass RepositoryRole 5, active.
- PASS .config/tend.yaml
merge: restricted(line 2); every tend-*.yamlmerge: restrictedonly. - PASS dormouse-bot permission: permission=write, role_name=write (no maintain/admin).
- PASS environments admitted refs: vscode-extension-publish v*; release-attest v*; security-audit main + v*; tend main; hosted-production/hosted-release-tag main; hosted-preview (exempt) main + refs/pull/*/merge. All custom_branch_policies, none null/protected_branches.
- PASS secret inventory: repo = ARGOS_TOKEN, CHROMATIC_PROJECT_TOKEN only; org secrets empty; security-audit = AUDIT_PAT + CLAUDE_CODE_OAUTH_TOKEN; tend = CLAUDE_CODE_OAUTH_TOKEN + TEND_BOT_TOKEN; vscode-extension-publish = OVSX_PAT + VSCE_PAT; release-attest empty secrets and no variables; no ANTHROPIC_API_KEY at any level.
- PASS secrets.allowed in .config/tend.yaml lists CHROMATIC_PROJECT_TOKEN and ARGOS_TOKEN.
- PASS workflow-audit.yaml active; last successful run 2026-10-01T14:24:49Z (<48h; now 2026-10-02 10:31Z).
- PASS Renovate cannot update tend-.yaml: packageRules entry matchFileNames tend-.yaml enabled:false (renovate.json).
- PASS workflow-audit lower bound: SINCE from previous successful run
created_at(workflow-audit.yaml:86-92), fallback 25h only when none exists. - PASS default_workflow_permissions=read, can_approve_pull_request_reviews=false.
- PASS Hosted environments (hosted-preview, hosted-production, hosted-release-tag): custom branch policies main (preview also refs/pull/*/merge), 2 required reviewers (nedtwigg, edgartwigg), can_admins_bypass false. Secrets only in Hosted environments, none at repo/org; production creds (DATABASE_URL, BACKUP_AGE_IDENTITY) not in preview.
- PASS HOSTED_TAG_TOKEN only in hosted-release-tag; only
tagjob in hosted-production.yml uses that environment. - PASS hosted preview: deploy requires same-repo head, needs verify; cleanup checks out refs/heads/main; production tag
needs: deploy(live verification step). - PASS vscode-extension-publish: 2 reviewers, prevent_self_review true, can_admins_bypass false.
- PASS release.yml publish-vscode has environment vscode-extension-publish; VSCE_PAT/OVSX_PAT referenced only at release.yml:347,359 inside it.
- PASS release.yml no production signing secrets (only GITHUB_TOKEN); ephemeral Tauri key generated (lines 70-81).
- PASS sign-and-deploy.sh: gh attestation verify (455), sha256 manifest check (417-464), jsign --storetype PIV (763).
- PASS TAURI_SIGNING_PRIVATE_KEY via env only (839); EV_SIGN_PIN
--storepass env:EV_SIGN_PIN(764,777). - PASS security-audit.md workflow gate: security-audit.yaml active; release.yml dispatches via
gh workflow run(282),gh run watch --exit-status(308), publish-vscodeneeds: security-audit(312-315). - PASS spec scope ownership: each of the 6 security*.md specs is in exactly one prompt's Scope; all named files exist; spec-lint OK.
- PASS fan-out: security-audit.yaml
--agentshas four dedicated domains; application-security and hostedmodel: opus, floor--model sonnet(149-152); security-audit-local.sh same split (69-70). - PASS prompt files: all five prompts + _preamble exist in .github/audit/; local script uses AUDIT_DIR=.github/audit.
- PASS qualitative scope coverage: application-security takes the remainder by subtraction; dotfile dirs named in ci-and-secrets prompt.
- PASS workflow-audit WINDOW: single array (.github/workflows/ .config/tend.yaml .github/audit/ .vscode/) feeds commit list, own_changes, is_clean_merge, classifiers via
${WINDOW[@]:1}. - PASS orchestration: orchestrator.md has until-loop, persisted $RUNNER_TEMP/audit-deadline (1920s), sentinel-based
finished(), requires audit-report.md; BASH_DEFAULT_TIMEOUT_MS=600000 > 540s break; timeout-minutes 40 > 32. - PASS reporting/redaction/AUDIT_PAT pre-check: redactor step covers transcript, audit-report.md and AUDIT_FRAGMENTS and rm -f's on throw (211-255); fragment guards unconditional, exact
VERDICT: PASS,VERDICT: FAIL*dissent, sentinel check; AUDIT_PAT pre-check present (69-77). scripts/security-audit.test.mjs 49/49 pass. - PASS regen boundary: workflow-audit.yaml accepts only mode 100644/100755 blobs (269-273); workflow-audit.test.mjs 27/27 pass; sign-and-deploy.test.mjs 37/37 pass.
Qualitative findings
- INFO: stray sibling-domain fragments (audit-application.md, audit-hosted.md, audit-supply-chain.md) sit at the repo root during the run; expected, no action.
- INFO: .vscode has no
runOn: folderOpentask; .claude/settings.json allowlist is read-only/test commands; no .mcp.json; website/public/standalone-latest.json URLs point at github.com/diffplug/dormouse releases with Tauri signatures. - INFO: Hosted environments allow self-review (prevent_self_review false), matching security-ci.md ("self-review is allowed").
- INFO: release-attest and tend environments have can_admins_bypass true; not covered by a FAIL IF (only vscode-extension-publish and Hosted environments are), no change from spec.
Application security
VERDICT: FAIL
FAIL IF results
Checks were split across seven delegates (A: local terminal/browser/socket/persisted; B: loopback/viewer/network policy; C: remote trust boundary/relay origin; D: credentials/setup password/cross-origin; E: network posture/what crosses; F: direct path/one-time/revocation; G: catch-all sweep). Their results are merged below verbatim.
Delegate A
Delegate A (security-local.md: terminal output, browser panes, dor socket, persisted state)
- PASS: security-local.md#Terminal output — TerminalProtocolParser consumes OSC 52 / OSC 50 — evidence: lib/src/lib/terminal-protocol.ts:113 OSC_CONSUMED_IDS has '50','52'; :324 parseOsc52 (always returns array); :925-928 isKnownUnsupportedIterm2Osc consumes 50
- PASS: security-local.md#Terminal output — every parse site runs before pty:data leaves it — evidence: standalone/sidecar/main.js:76
if (event !== 'data') send(...)(raw data never sent, host.onPtyEvent parses); lib/src/host/remote/sidecar-entry.ts:186 onChunk -> pty:data after createOwnerPtyStream; vscode-ext/src/message-router.ts:487-489 posts only onProcessedPtyData visibleData; replay parsed by parseReplay (lib/src/lib/platform/replay-parse.ts:16) in vscode/tauri/browser-sidecar adapters - PASS: security-local.md#Terminal output — OSC 52 reaches clipboard only as user-chosen copy-editor program format — evidence: terminal-protocol.ts:936-943 emits clipboardOffer only; all adapters route it to offerProgramCopy (vscode-adapter.ts:131, standalone/src/tauri-adapter.ts:166, fake-adapter.ts:485); clipboard written only by copySelection (copy-selection.ts:17-21 via editorRendering(copyEditor, programCopy))
- PASS: security-local.md#Terminal output — OSC 52 bounded and control-stripped (only \n and \t kept) — evidence: terminal-protocol.ts:940 data.length > CLIPBOARD_OFFER_LIMIT(16000) drops; lib/src/lib/osc-sanitize.ts:43-45 strips [\x00-\x08\x0b-\x1f\x7f-\x9f]
- PASS: security-local.md#Terminal output — OSC 52 dropped in a pane with no shadowed drag — evidence: lib/src/lib/mouse-selection.ts:195-198 returns unless selection.owner === 'program'
- PASS: security-local.md#Terminal output — retained values bounded and control-stripped — evidence: titles/bodies sanitizeText(TITLE_LIMIT/BODY_LIMIT) terminal-protocol.ts:345,379,459,913; OSC 99 pending capped (OSC99_MAX_PENDING_IDS=64, TTL, appendLimited :446-448); cwd boundedCwdValue (terminal-state.ts:784-789, MAX_CWD_LENGTH=4096) applied :252,261,265,279,697
- PASS: security-local.md#Terminal output — COMMAND_LINE_LIMIT binds after unescape with 4x pre-bound — evidence: terminal-protocol.ts:734-741 truncateText(encoded, COMMAND_LINE_LIMIT*encodedWidth) then sanitizeCommandLine(decode(..), COMMAND_LINE_LIMIT); 633/133 \xNN width 4 (:721), cmdline_url width 12 (:720) — spec mentions only the 4x form (minor drift, not a weakness)
- PASS: security-local.md#Terminal output — OSC 8 activation never reaches openExternal without the dialog — evidence: lib/src/lib/terminal-lifecycle.ts:144-149 linkHandler -> activateTerminalLink; lib/src/lib/terminal-link-activation.ts:35-37,51 non-preview or refused paths call requestExternalLinkConfirmation only; sole openExternal on that path is ExternalLinkModalHost.tsx:25-27 confirm()
- PASS: security-local.md#Terminal output — dialog renders no open action for a deceptive verdict (host also refuses) — evidence: lib/src/components/ExternalLinkModal.tsx:110-128 deceptive branch offers Close + Copy only; ExternalLinkModalHost.tsx:25
verdict !== 'deceptive'gate - PASS: security-local.md#Terminal output — preview path only when display text is a whole-component suffix of decoded target — evidence: lib/src/lib/external-links.ts:113-118 (control chars refused;
path === text || path.endsWith('/'+text)) - PASS: security-local.md#Terminal output — host opens file: URLs only for empty/localhost/this-machine host — evidence: lib/src/host/tool-input.ts:45-56 localFileUrlPath -> namesThisHost(url.hostname) else ToolFileError; controls re-checked after decode and after realpath (:19-35)
- PASS: security-local.md#Terminal output — OSC 367 open never dispatched from replay — evidence: lib/src/lib/tool-events.ts:23-36 recordToolEvents (used by parseReplay, replay-parse.ts:18) has no toolOpen branch; dispatchToolOpens only via applyLiveToolEvents (vscode-adapter.ts:127, tauri-adapter.ts:158, browser-sidecar-adapter.ts:333, fake-adapter.ts:479)
- PASS: security-local.md#Terminal output — OSC 367 open only from a Tool running its designated command — evidence: lib/src/components/wall/use-dor-control.ts:1122-1128 requires isToolParams(meta) and currentCommand.rawCommandLine === tool.command
- PASS: security-local.md#Terminal output — OSC 367 open path absolute and control-free — evidence: dor-tools-lib/src/osc.ts:124-135 validToolOpenPath (bounded, leading / or drive, no [\u0000-\u001f\u007f-\u009f])
- PASS: security-local.md#Terminal output — control-socket request cannot set oscOpen — evidence: lib/src/lib/platform/dor-control-dispatch.ts:35,45-53 detail built field-by-field from payload (requestId/surfaceId/method/params), oscOpen only from the 3rd arg; only lib/src/lib/tool-open-requests.ts:33-40 passes {oscOpen:true} (wire callers vscode-adapter.ts:154, tauri-adapter.ts:233, browser-sidecar-adapter.ts:360 pass none)
- PASS: security-local.md#Terminal output — error-viewer argv carries no control character — evidence: use-dor-control.ts:1392-1393 openFile is the validated OSC path; message .replace(/[\x00-\x1f\x7f-\x9f]+/g,' ')
- PASS: security-local.md#Browser panes — shim targets only its proxy origin and the chain's innermost origin — evidence: lib/src/host/iframe-proxy-rewrite.ts:113 send() posts to location.origin and TARGET only (never '*'); TARGET = grant.embedderOrigins[0] (lib/src/host/iframe-proxy.ts:268,519)
- PASS: security-local.md#Browser panes — shim relays no nested location, foreign-origin, or unregistered message — evidence: iframe-proxy-rewrite.ts relay listener requires e.origin===location.origin and forwards only leader/pointerdown/open-window(string url); 'location' not relayed; theme listener requires e.source===P && e.origin===TARGET
- PASS: security-local.md#Browser panes — proxy uses a chain only if validated in full — evidence: iframe-proxy-rewrite.ts:67-77 normalizeEmbedderOrigins returns null on any non-string / non-serialized-origin entry, empty, or >8; iframe-proxy.ts:133-137 null chain => pass-through, no shim
- PASS: security-local.md#Browser panes — VSCodeAdapter listeners act only after isHostMessage — evidence: lib/src/lib/platform/vscode-adapter.ts:100-103 and :215 check isHostMessage before reading type; lib/src/lib/vscode-message-token.ts:46-50 fails closed on null token
- PASS: security-local.md#Browser panes — token minted per serve, attached only by WebviewChannel.post — evidence: vscode-ext/src/webview-html.ts:155-165 randomBytes(24) per getWebviewHtml; vscode-ext/src/webview-messaging.ts:34-41 serveWebview stamps it in post(); all other posts go through channel.post (webview-view-provider.ts:23-24; grep shows no other webview.postMessage)
- PASS: security-local.md#The dor control socket — ensureControlDir requires real dir, not symlink, owned by uid, exactly 0700 — evidence: standalone/sidecar/dor-control-server.js:88-96 (lstat-based isDirectory && !isSymbolicLink && uid===uid && (mode&0o777)===0o700); chmod only when already ours (:80-87)
- PASS: security-local.md#The dor control socket — resolveControlSocketPath refuses when the predicate fails — evidence: dor-control-server.js:118-119
if (!safeDir) return null(win32 named pipe branch :113-116 has no dir, by design); VS Code reuses the same module (vscode-ext/src/pty-host.js:7) - PASS: security-local.md#The dor control socket — raw token never reaches a socket — evidence: server writes challenge nonce + HMAC welcome only (dor-control-server.js:236,251); client writes hello{nonce,proof} then request{requestId,surfaceId,method,params,timeoutMs} (dor/src/control-client.ts:314-334), no token field
- PASS: security-local.md#The dor control socket — both sides compare proofs only via SHA-256-then-timingSafeEqual — evidence: dor-control-server.js:29-34,247; dor/src/control-client.ts:82-86,323; constructions identical (HMAC-SHA256(token,
${domain} ${nonce}) hex at server :19-20, client :78-79) - PASS: security-local.md#Persisted state — write_file_atomically restricts dir 0700 and file 0600 on unix before bytes — evidence: standalone/src-tauri/src/lib.rs:1815-1825 ensure_parent_with restrict(dir,0o700); :1849-1853 restrict(&tmp,0o600) before write_all; unix arm :1683-1687
- PASS: security-local.md#Persisted state — Windows arm applies a protected DACL with exactly one current-user ACE — evidence: lib.rs:1695-1797 single EXPLICIT_ACCESS_W (FILE_ALL_ACCESS, TokenUser SID) via SetEntriesInAclW(NewAcl=None) + SetNamedSecurityInfoW(DACL|PROTECTED_DACL); test restrict_to_owner_leaves_one_owner_only_ace at :4827
- PASS: security-local.md#Persisted state — every lib.rs writer under the state root goes through it — evidence: grep of fs::write/File::create/OpenOptions in standalone/src-tauri/src/*.rs: non-test writers are write_file_atomically callers (:1880 session, :1994 legacy-transcript scrub, :2248 geometry, :2488 arrivals.json) plus the log (:886,:902; known gap in security-local.md 'standalone log'), the dor-node.exe cache copy (:3566, cache dir not state root), and clipboard_win.rs:174 (temp_dir drop file)
- PASS: security-local.md#Persisted state — named pin tests exist — evidence: lib.rs:5200 session_permission_failures_preserve_previous_snapshot_without_writing_bytes, :5228 session_write_tightens_directory_and_existing_temp_file
Qualitative (security-local.md delegate A: terminal output, browser panes, dor socket, persisted state)
- INFO: Iframe-proxy framing — replacement is exactly
frame-ancestors 'self' <validated chain>(lib/src/host/iframe-proxy-rewrite.ts:84-86); upstream CSP kept only with x-dormouse-preserve-csp and then intersected (iframe-proxy.ts:404-415); null chain keeps X-Frame-Options/CSP (replaceFraming=false, :393) and passThrough injects no shim (:274); serveErrorPage likewise uninstrumented with no chain (:515-526). Shim message targets are location.origin + TARGET, never '*'. No defect found. - INFO: OSC id routing is by literal decimal string (terminal-protocol.ts:873-881), so
OSC 052;.../OSC 050;...are forwarded to xterm.js, which parses the id numerically as 52/50. Harmless today: no ClipboardAddon or OSC 50/52 handler is registered (grep of lib/src, standalone/src, vscode-ext/src, website/src). Would become a bypass of the 'consume OSC 52' rule if a clipboard addon were ever loaded; consider normalizing leading zeros in oscDispositionAt. - INFO: OSC 367 open gate compares currentCommand.rawCommandLine (shell-reported via OSC 633 E / 133 C) with tool.command (use-dor-control.ts:1124-1125). A later process in the same Tool pane, after the designated command exits, can forge that report and pass the gate. Confined to a pane already designated as a Tool; noting because the spec phrases the check as 'running its designated command'.
- INFO: validToolOpenPath accepts any leading '/' (dor-tools-lib/src/osc.ts:124-127), so on Windows a running Tool can name
//server/share/x, which resolveLocalToolTarget realpaths (lib/src/host/tool-input.ts:29), touching SMB. Limited to a running trusted Tool; the OSC 8 path is safe because fileURLToPath rejects host-less UNC URLs. - INFO: Sweep of lib/src/host, dor/src, dor-lib-common/src, standalone/sidecar for command construction: all spawns are argv-based (spawnAndCapture/cross-spawn, execFile). No shell:true. runGit runs only rev-parse/config --get (no index read, so no fsmonitor) with dir in argv and no attacker cwd (lib/src/host/git-cli.ts:13-14, git-info.ts:70-72). Browser CLIs resolve the binary to an absolute path before spawning (dor/src/commands/browser-cli.ts:365-418). standalone/sidecar/clipboard-ops.js:167 builds AppleScript by escaping only '"' in the output path, not '\'. The path is host-generated, so this is not exploitable. Escaping backslashes too would be safer.
- INFO: Terminal context directory actions: openDirectory checks for an absolute, NUL-free, existing directory, then realpaths it and passes it as a single argv to explorer.exe/open/xdg-open (standalone/sidecar/pty-core.js:1626-1632, 1179-1193). This matches the security-local.md rule. Unverified residual: explorer.exe parses its own command line, with commas acting as separators, so a canonical directory path containing commas could be read as more than one argument. Not exploited or tested here.
Delegate B
Delegate B: Loopback Listeners, Local-file viewer, Network policy
- INFO: loopback-lint run —
node scripts/loopback-lint.mjs-> "loopback-lint: OK (2 allowlisted)", 8 non-test listeners: dor-tools-builtin/src/viewer-server.ts:94, hosted/server/dev.ts:46, lib/src/host/browser-viewer.ts:112, lib/src/host/iframe-proxy.ts:197, scripts/direct-interop/run.mjs:405, scripts/dor-tool-qc/server.mjs:25, standalone/scripts/dev-agent-browser.mjs:279, standalone/scripts/dev-run.mjs:27;node scripts/loopback-lint-selftest.mjs-> OK (13 load-bearing checks) - PASS: docs/specs/security-local.md#Loopback Listeners — iframe proxy never rewrites Origin for a non-own caller (handleRequest) — evidence: lib/src/host/iframe-proxy.ts:226
if (isOwnOrigin(req.headers.origin, grant.port)) headers.origin = grant.upstream.origin;in upstreamRequestHeaders, used at :247 - PASS: docs/specs/security-local.md#Loopback Listeners — same for handleUpgrade — evidence: lib/src/host/iframe-proxy.ts:461 handleUpgrade calls upstreamRequestHeaders
- PASS: docs/specs/security-local.md#Loopback Listeners — iframe proxy strips Cookie upstream on HTTP and WS — evidence: lib/src/host/iframe-proxy.ts:227
delete headers.cookiein shared upstreamRequestHeaders - PASS: docs/specs/security-local.md#Loopback Listeners — strips Set-Cookie downstream on HTTP, 101 handshakes, and refused upgrades — evidence: iframe-proxy.ts:399 (sanitizeResponseHeaders), :477 (101 rawHeaders loop), :488-492 refused upgrade goes through passThrough->sanitizeResponseHeaders
- PASS: docs/specs/security-local.md#Loopback Listeners — Host names own grant port on both paths — evidence: iframe-proxy.ts:232 and :456
isLoopbackHost(req.headers.host, grant.port)refuse (421 / socket.destroy) before lastUsed - PASS: docs/specs/security-local.md#Loopback Listeners — framing headers replaced with exactly frame-ancestors 'self' ; no usable chain preserves headers and injects nothing — evidence: iframe-proxy.ts:400-413 (drop only when embedderOrigins!==null, then append frameAncestorsCsp), :260-267 embedder===undefined -> passThrough (no shim); iframe-proxy-rewrite.ts:67-86 normalizeEmbedderOrigins strict SERIALIZED_ORIGIN_RE, frameAncestorsCsp; preserved upstream CSP only intersects
- PASS: docs/specs/security-local.md#Loopback Listeners — shim posts only to its own proxy origin and the chain's innermost origin — evidence: iframe-proxy-rewrite.ts:119
P.postMessage(m,location.origin)+P.postMessage(m,TARGET), TARGET=embedderOrigins[0] (iframe-proxy.ts:258, :518) - PASS: docs/specs/security-local.md#Loopback Listeners — foreign Origin does not refresh idle timer; absent Origin does — evidence: iframe-proxy.ts:245 and :460
if (!isForeignOrigin(req.headers.origin, grant.port)) grant.lastUsed = Date.now(); - PASS: docs/specs/security-local.md#Loopback Listeners — no loopback listener grants an unrecognized caller extra privilege (all 8 non-test listeners inspected) — evidence: viewer-server.ts:80-94 (see Local-file viewer lines); hosted/server/dev.ts:31,44 allowedDevRequest (exact Host+Origin, sec-fetch-site!=cross-site) on HTTP and upgrade; lib/src/host/browser-viewer.ts:104 Host+single-use grant, HTTP 403; iframe-proxy.ts admits-all/vouches-none; scripts/direct-interop/run.mjs:353,365 isAuthorized (token/Host/JSON) + isOwnOrigin for POST; scripts/dor-tool-qc/server.mjs allowlisted unshipped fixture; standalone/scripts/dev-agent-browser.mjs:231 isAuthorized before routing; standalone/scripts/dev-run.mjs:24-51 cors:false, allowedHosts:[]. Independent grep for createServer/.listen(/serve(/WebSocketServer over tracked non-test JS/TS found no extra loopback listener (others: relay/ out of scope, Unix socket/pipe in standalone/sidecar/dor-control-server.js:351 and vscode-ext/src/peer-link.ts:749)
- PASS: docs/specs/security-local.md#Loopback Listeners — lint scans all tracked JS/TS and fails an unguarded new non-test listener; every BIND_FORMS form has a self-test fixture — evidence: scripts/loopback-lint.mjs:127-150 BIND_FORMS (6 labels) / SOURCE_EXT; scripts/loopback-lint-selftest.mjs FIXTURES cover all 6 labels plus .mts and test-file cases; run -> "loopback-lint-selftest: OK (13 load-bearing checks)"
- PASS: docs/specs/security-local.md#Loopback Listeners — browser viewer upgrades only with own loopback Host and a single-use 60s grant for one view — evidence: lib/src/host/browser-viewer.ts:104
token && isLoopbackHost(req.headers.host, port) ? grants.consume(token); lib/src/host/browser-stream-guard.ts:12-20 randomBytes(32), expires now+60_000, delete on consume - PASS: docs/specs/security-local.md#Loopback Listeners — provider receives only rebuilt webview messages — evidence: browser-viewer.ts:332 parseViewerInput(raw) and :476-525 constructs fresh objects per type, default null
Truncated to fit: the full body is 182443 characters. The untruncated audit-report.md is in this run's audit-transcript artifact (download).
- Lingua principale
- TypeScript
- Stelle
- 5
- Fork
- 1
- Merge medio
- 11h 50m
- PR unite (30g)
- 353
Preparare l'ambiente
Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di diffplug/dormouse
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 86/100
diffplug/dormouse#912 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
diffplug/dormouse#968 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 42/100
diffplug/dormouse#910 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
review-runs-tracking
Difficoltà 5/5 Più di una settimana Idoneità per principianti 10/100
diffplug/dormouse#881 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 38/100
diffplug/dormouse#845 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di diffplug/dormouse
Issue simili
-
enhancement
Difficoltà 2/5 1-3 ore Idoneità per principianti 86/100
tomjn/coilbox-hub#454 ·
I maintainer di solito rispondono entro 1 giorno
-
enhancement
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
I maintainer di solito rispondono entro 1 giorno
-
api: spanner
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
googleapis/google-cloud-node#9513 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 92/100
I maintainer di solito rispondono entro 1 giorno
-
SegmentedControl calls Math.random() during render, breaking Next.js cacheComponents prerenderingAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
mantinedev/mantine#9244 ·
I maintainer di solito rispondono entro 8 giorni