Repository navigation
Add the flight recorder: hash-chained session recordings with replay and verify - #7
Merged
Merged
Conversation
…and verify Every serve-mode session is now recorded to a JSONL file: each client request, each response the guard returns, upstream notifications, and every guard decision (policy denial, pin denial, observe-mode would-deny, hidden tools). Each record carries the hash of the previous one and its own hash, so edits, deletions, insertions and reordering break the chain at a known record. With [recorder] signing_key_env set, hashes are HMAC-SHA256 under a key the writer and verifier share, so a forger without the key cannot recompute the chain. Payloads are redacted before hashing with built-in patterns (private keys, AWS, GitHub, Slack, OpenAI, Anthropic, Google, Stripe and mcp-guard keys, JWTs, bearer tokens, credentials in URLs) plus the user's [audit] redaction_rules, and truncated above max_payload_bytes with the hash of the full original kept, so a recording can be shared without leaking secrets. New commands: - mcp-guard replay: timeline of a session with arguments, outcomes and decisions; --list, --denied, --tool, --json; reports chain status. - mcp-guard verify: recompute the chain for one or all sessions, name the first bad record, exit 1 on tampering; checks signatures when the key is present and says so when it is not. wrap enables the recorder for every wrapped server under <config dir>/recordings/<client>-<server>/; doctor reports RECORDER_DISABLED. A recorder failure is logged and never blocks the agent. Docs: new docs/flight-recorder.md (format, redaction, tamper-evidence model and its limits, operations), plus local-mode, configuration, CLI reference, template, CHANGELOG, README and CLAUDE.md. Tests: unit tests for chaining, tamper detection (edit, removal, reorder, garbage line), signed chains, redaction, truncation, include_results, session listing; a proxy test asserting the record sequence for a call and a denial; e2e tests running a live serve session then replay and verify, tampering the file, and signed recordings with, without and with the wrong key. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JKKYdbt8Gd5B9Q4C3wim3f
botzrDev
marked this pull request as ready for review
October 22, 2026 18:07
This was referenced Oct 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Third roadmap item after local mode (botzrDev/mcp-guard#5) and argument-level policy (botzrDev/mcp-guard#6): evidence. The audit log says a tool was called. The flight recorder keeps what was asked, what came back, and what the guard blocked, in order, in a form that can be proven unedited.
What it records
Every
mcp-guard servesession becomes one JSONL file: each client request, each response the guard returns, upstream notifications, and every guard decision (policy_deny,pin_deny,policy_would_deny,tool_hidden_policy,tool_hidden_pin).session_startcarries the upstream command, config path, policy mode and guard version;session_endsays why the session ended.Tamper evidence
Each record carries
prev(the previous record's hash) andhash(over its own contents prefixed byprev). Editing, deleting, inserting or reordering a record breaks the chain at a known point. With[recorder] signing_key_envset, hashes are HMAC-SHA256 under a shared key, so a forger who can edit the file but lacks the key cannot rechain it. The docs are explicit about what plain hashes do and do not protect against.Redaction
Payloads are redacted before hashing: built-in patterns for private key blocks, AWS, GitHub, Slack, OpenAI, Anthropic, Google, Stripe and mcp-guard keys, JWTs, bearer tokens and
user:password@URLs, plus the user's[audit] redaction_rules. Oversized payloads are truncated to a preview.payload_sha256is the hash of the original, so a payload you still hold can be matched to a record without the recording containing the secret.New commands
mcp-guard replay [--list] [--session latest|<id>|<file>] [--denied] [--tool X] [--json]renders a session as a timeline and reports chain status.mcp-guard verify [--session latest|all|...] [--json]recomputes the chain, names the first bad record, exits 1 on tampering, and checks HMAC signatures when the key is present (marksOK*when it is not).mcp-guard wrapenables recording for every wrapped server under<config dir>/recordings/<client>-<server>/.doctorreportsRECORDER_DISABLED. Recorder failures are logged and never block the agent; nothing is ever written to stdout.Docs
New
docs/flight-recorder.md(format, field table, redaction, the tamper-evidence model and its limits, operations). Updateddocs/local-mode.md,docs/configuration.md,docs/cli.md, the config template, CHANGELOG, README and CLAUDE.md.Verification
cargo fmt --all -- --checkcargo clippy --all-features -- -D warnings(CI command)RUSTDOCFLAGS=-D warnings cargo doc --no-deps --all-featurescargo test --all-featurescargo test --workspaceNew tests:
include_results = falsekeeping errors; session listing and selection.servesession recorded, thenreplay --list,replay,replay --denied,verify --session all, tampering the file and seeingverifyfail with the record number andreplayreportCHAIN BROKEN; a signed session verified with, without and with the wrong key; clear messages when there are no recordings.The e2e helper gained a graceful
close()that drops stdin and waits, matching how real clients exit, sosession_endis exercised.Next
Recording in gateway mode keyed by identity, retention, and a self-contained HTML session report, then the 2026-07-28 protocol shim.
Generated by Claude Code