Skip to content

security: STRIDE verification audit — fixes (E-5, T-5, T-4), truth-up, claim/evidence CI gate#39

Merged
noisyloop merged 1 commit into
mainfrom
claude/stride-truthup-fixes
May 18, 2026
Merged

security: STRIDE verification audit — fixes (E-5, T-5, T-4), truth-up, claim/evidence CI gate#39
noisyloop merged 1 commit into
mainfrom
claude/stride-truthup-fixes

Conversation

@noisyloop

@noisyloop noisyloop commented May 18, 2026

Copy link
Copy Markdown
Owner

Summary

After D-6 was found marked ✅ resolved without an implementation, every STRIDE claim was re-audited line-by-line against the code. The pattern repeated. This PR fixes the genuine gaps (with attack-path regression tests), truth-ups the docs so they stop overstating coverage, and adds a CI gate that structurally prevents this class of drift from recurring.

Audit result (24 claims)

Verdict Findings
Genuinely implemented & wired 17 (T-1, T-3, R-1, R-2, R-3, S-4, E-3, E-4, I-1, I-2, I-3, I-4, D-1, D-2, D-3, D-4, T-6)
Was a gap → fixed in this PR E-5, T-5, T-4
❌ aspirational, left honest E-2 (worker-thread isolation — IsolatedAgentRunner exists, zero callers; agents run in-process)
⚠️ oversold, downgraded S-1 (external-replay only), S-3 (no caller auth, only post-startup lock), T-2 (key falls back to EOS_AGENT_SECRET)
Real fix, residual footgun S-2/E-1 (core fix solid; server.ts still exposes unauthenticated /api/approvals/:id/{approve,deny} emitting an unconsumed event — dead code, not a live bypass)

Real fixes (each with a regression test that demonstrates the attack path)

  • E-5core/AgentRegistry.register() silently unregister()d + overwrote a duplicate id (agent identity is the trust anchor for ApprovalGate trustedAgents). Now rejects the collision and emits a safety.violation audit event.
  • T-5 — plugin sandbox resolved msg.result raw into prompts. Added bounded recursive sanitizePluginResult(): every string passes the injection pipeline; depth/node caps; injection audited.
  • T-4 — decision ledger had per-entry hashes only (deletion/reordering undetectable). Now every entry carries previousHash chained from GENESIS; streaming verifyChain() fails closed on tamper/deletion/reorder; legacy pre-chain entries stay verifiable; chain head bootstraps from disk across restarts.

Docs truth-up

  • docs/STRIDE.md: added an legend + dated Verification Audit Corrections note; the Finding Summary table is now authoritative (E-2 ❌; S-1/S-3/T-2 ⚠️; T-4/T-5/E-5 ✅ dated; S-2/E-1 residual noted).
  • README.md: the "single-process architecture" limitation previously repeated the false E-2 worker_thread claim (introduced in PR Claude/fix glasswally agent glitch #38) — corrected to state plainly all agents share one process/heap; only the plugin sandbox is real isolation.

Structural fix — claim/evidence CI gate

scripts/check-stride-claims.mjs (npm run check:stride, wired into security.yml): every STRIDE finding must have a manifest entry; a must be test-backed (an attack-path test that references the id) or explicitly audit-attested with a code anchor; a non- must declare resolved:false. Doc and manifest cannot silently diverge — the gate already caught one such drift on T-4 during development. This is the durable fix for the D-6 class of bug.

Deliberately out of scope

  • E-2 (wire IsolatedAgentRunner): a runtime rearchitecture with high destabilization risk and modest marginal security given the verified in-process controls + the real plugin sandbox. Left honestly marked ❌ as a roadmap decision (per maintainer: may be downgraded rather than built).
  • Removing the dead server.ts approval endpoints (touches external API surface) — flagged in docs, not removed here.

Test plan

  • npm test126/126, 10 suites
  • npm run check:stride — PASS (29 findings: 4 test-backed, 19 audit-attested, 6 not-resolved)
  • New attack-path suites: agent-registry-collision (E-5), plugin-return-sanitization (T-5), decision-ledger-chain (T-4: tamper / deletion / reorder / legacy back-compat)
  • e2e unaffected; typecheck clean (only the pre-existing stale non-test tests/security/model-guard.ts errors remain, untouched)

A line-by-line re-audit of every "✅ resolved" STRIDE finding (prompted
by D-6 being marked done without an implementation) found more of the
same pattern. This commit fixes the two small real gaps and corrects the
docs so the threat model stops overstating coverage.

Real fixes (with regression tests):
- E-5: core/AgentRegistry.register() silently unregistered+overwrote a
  duplicate agent id — a malicious agent could seize a trusted agent's
  identity with no signal. Now rejects the collision (throws) and emits a
  safety.violation audit event. Legit re-register after unregister still
  works.
- T-5: plugin-sandbox resolved msg.result raw — untrusted plugin output
  flowed into prompts unsanitized. Added bounded recursive
  sanitizePluginResult(): every string passes the injection pipeline;
  depth/node caps stop a pathological return; injection is audited.

Docs truth-up (STRIDE.md table is now authoritative + audit note):
- E-2 ❌ not implemented (IsolatedAgentRunner exists but unwired; agents
  run in-process — the architecture diagram was already correct).
- T-4 ❌ not implemented (per-entry hash only; no cross-entry chain).
- S-1 / S-3 / T-2 ⚠️ downgraded (oversold: external-replay-only;
  no caller auth; key falls back to EOS_AGENT_SECRET).
- S-2/E-1 residual noted (dead unauthenticated server.ts approval
  endpoints emit an unconsumed event — re-introduction footgun).
- README "single-process" limitation corrected: it previously repeated
  the false E-2 worker_thread claim.

Full suite 121/121.

https://claude.ai/code/session_01ArAvRMiZgCwF5oNj3r94Ap
@noisyloop noisyloop merged commit 7098145 into main May 18, 2026
12 checks passed
@noisyloop noisyloop changed the title security: STRIDE verification audit — fix E-5/T-5, truth-up false ✅ claims security: STRIDE verification audit — fixes (E-5, T-5, T-4), truth-up, claim/evidence CI gate May 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants