Skip to content

security(cli): round-2 audit follow-ups on the bridge - #57

Merged
runyourempire merged 1 commit into
mainfrom
harden-round2-audit
Jul 13, 2026
Merged

security(cli): round-2 audit follow-ups on the bridge#57
runyourempire merged 1 commit into
mainfrom
harden-round2-audit

Conversation

@runyourempire

Copy link
Copy Markdown
Collaborator

Second adversarial verification pass (two internal red-team reviewers) on the remediated bridge (post-#56). Both confirmed the round-1 fixes are correct and complete — finding #1's re-resolve covers every token-bearing path (top-of-forward scan and the retry-loop reconnect, both through scan_once's dir_is_trusted + identity gate, locked in by the regression test); #3 complete; restart recovery, stdout serialization, poison-recovery, and single-writer backend_up all intact.

Fixed (2 Low)

  • Finish MCP client should auto-recover from 422 stale-session (after app/server restart) instead of wedging #2 (was PARTIAL): the non-SSE relay JSON-validated the body but relayed it verbatim — a valid but pretty-printed body could be split across stdout lines and break a newline-delimited client. Now relays the compact re-serialized form (parsed.to_string()), matching the SSE path. (Not attacker-reachable — the backend is trust-gated Victauri, which emits compact JSON.)
  • Close the client_ready lost-edge: if the backend came up during the init-handshake window, the poller consumed the down→up edge without emitting; the notifications/initialized handler now emits list_changed once if the backend is already up (idempotent).

Documented residuals (pre-existing, not introduced; deferred with rationale in code + brief)

  • Liveness is PID-based; /health carries no token, so PID-reuse + port-reuse can theoretically defeat it. Per-call re-resolve shrinks it to a per-call coincidence; full close needs mutual auth on /health (plugin-side).
  • Windows dir_is_trusted is an assumption (per-user %TEMP%), not a verified ACL check; a redirected shared TEMP is unguarded on Windows.
  • A tool call racing the sub-second restart gap fails fast by design (audit Red-team / audit release hardening (P1 blockers + 2 missed defects) #1 forbids reusing a cached connection).

Verification

Full gate green: fmt --all, clippy --workspace --all-targets -D warnings (1.97), test -p victauri-cli (46 unit + 3 e2e). Re-verified live against 4DA: 3/3 fresh cold-connects, live tools + working call.

🤖 Generated with Claude Code

A second adversarial pass (two internal red-team reviewers) on the remediated
code. Both confirmed the round-1 fixes are correct and complete: finding #1's
re-resolve covers EVERY token-bearing path (top-of-forward scan AND the
retry-loop reconnect, both via scan_once's dir_is_trusted + identity gate, proven
by the regression test); #3 is complete; restart recovery, stdout serialization,
poison-recovery, and single-writer backend_up are intact. Two Low items fixed
here, plus honest documentation of pre-existing residuals:

- Finish #2 (was PARTIAL): the non-SSE relay JSON-VALIDATED the body but relayed
  it verbatim, so a valid multi-line (pretty-printed) body could be split across
  stdout lines by writeln! and break a newline-delimited client. Now relays the
  compact re-serialized form (parsed.to_string()) — one line, matching the SSE
  path. Low (not attacker-reachable: the backend is trust-gated Victauri, which
  emits compact JSON).
- Close the client_ready lost-edge: if the backend came up during the
  init-handshake window, the poller consumed the down->up edge without emitting
  (client not ready yet) and no fresh edge followed. The notifications/initialized
  handler now emits list_changed once if backend_up is already true (idempotent).

Documented residuals (pre-existing, not introduced; deferred with rationale):
- Liveness is PID-based; /health carries no token and doesn't authenticate the
  listener, so PID-reuse + port-reuse can theoretically defeat it. Re-resolving
  per call shrinks it to a per-call coincidence; a full close needs mutual auth
  on /health (plugin-side).
- Windows dir_is_trusted is an assumption (per-user %TEMP% not world-writable),
  not a verified ACL check; a redirected shared TEMP is unguarded on Windows.
- A tool call racing the sub-second restart gap fails fast by design (the audit
  #1 rule forbids reusing a cached connection).

Gate green: fmt --all, clippy --workspace --all-targets -D warnings (1.97),
test -p victauri-cli (46 unit + 3 e2e). Re-verified LIVE vs 4DA: 3/3 fresh
cold-connects, live tools + working call.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KfH8iYXUYm5YruHescthzD
@runyourempire
runyourempire merged commit 8a5da40 into main Jul 13, 2026
21 checks passed
@runyourempire
runyourempire deleted the harden-round2-audit branch July 13, 2026 12:27
runyourempire added a commit that referenced this pull request Jul 13, 2026
…58)

victauri-cli-only, semver-clean within ^0.8 (plugin + public Rust API
unchanged). Bundles: the bridge cold-start fix (#55 — connects in a fresh
terminal even with the app down), pre-emptive internal red-team hardening (#56),
external GPT audit remediation incl. a real token-leak fix + regression test,
and round-2 verification follow-ups (#57).

- scripts/bump-version.ps1 0.8.7 (workspace version, dep pins, action pin,
  CLAUDE.md refs, Cargo.lock)
- CHANGELOG [Unreleased] -> [0.8.7] - 2026-07-13
- MIGRATION.md v0.8.6 -> v0.8.7 (bridge connects in a fresh terminal; --wait
  no-op; per-forward trusted re-resolve)
- CLAUDE.md Current State -> v0.8.7

Gate green locally: fmt --all, clippy --workspace --all-targets -D warnings
(1.97), build --workspace, test -p victauri-cli (46 unit + 3 e2e). NOT published
(operator's crates.io gate).


Claude-Session: https://claude.ai/code/session_01KfH8iYXUYm5YruHescthzD

Co-authored-by: audit <audit@example.test>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant