Repository navigation
Redact registered secrets from hook and tool failure logs and tool-call events - #103
Merged
Merged
Conversation
…paired surrogates Redaction can lengthen a key or string past its JsonSnapshot limit; the event copy is now cut to the limit with a trailing ellipsis instead of failing the call. Redacting through UTF-8 turned unpaired surrogates into '?', which could collide distinct keys; the runs between them are redacted and the surrogates kept. Registered secrets are ASCII, so none spans one.
…und surrogates The event copy now reuses ToolRound's rule for tool results: text with nothing redacted is returned unchanged, so an unpaired surrogate in it never becomes ? and distinct keys stay distinct. The run-splitting helper goes; v3-simplify-redactor removes the UTF-8 round trip for every redaction site. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Redacting the call ToolRound passes to the PostToolUse hooks survived every test: the event test checked the tool and the history but no hook. The event test now records what a PostToolUse hook receives. Co-Authored-By: Claude Opus 5.5 <[email protected]>
ContextCompaction attached a ContextCompactor's exception, message and all, to its WARNING. A compactor works on the whole history, which holds user messages and hook-injected arguments unredacted, so a compactor that names what it failed on carried a registered secret into the record, as a hook did. The record now attaches SerializedError.redactedForLog. Co-Authored-By: Claude Opus 5.5 <[email protected]>
The README's secret-redaction section still listed ToolMutated arguments and ToolBlocked reasons as not covered, and the CHANGELOG and CLAUDE.md said "the hooks" see the arguments unredacted, though an OnStreamEvent hook sees the redacted event. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
StopClassifier and HookRegistry hold the session's secret registry, so the javadoc no longer calls them reusable across sessions. Co-Authored-By: Claude Opus 5.5 <[email protected]>
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.
Spec
audit-hook-event-redaction(P1, found by the PR #98 security and correctness reviewers).Logs.
SerializedError.redactedForLog(throwable, redactor)builds a copy of an exception for a log record: each level of its cause chain (bounded at 16) becomes<class>: <message>redacted against the session'sSecretRegistry, with that level's original frames; suppressed exceptions are not copied. Six session log lines attach it instead of the raw exception:HookRegistry's observer line, its stream-event line and thePreToolUseguard (which now carries the trace instead of the class alone),DispatchedCall's SEVERE for a tool that threw after its call was answered,SessionTeardown'sonSessionEndWARNING, andContextCompaction's compactor WARNING. Log message texts are unchanged.HookRegistry(hooks, secrets).SessionWiringpasses the session's registry;empty()uses an empty one.Events.
ToolUse,ToolMutated(call,inputBefore,inputAfter),ToolBlockedandToolResultcarry the arguments with every registered secret redacted, in keys and in string values at any depth (loop.RedactedArguments). A key or string with no secret is kept as it is; a key or string that redaction lengthens past itsJsonSnapshotlimit is cut to it, ending in…, so a valid call always has a valid event copy. The call that is authorized, dispatched, passed toPreToolUse/PostToolUsehooks and appended to the history keeps its arguments.Docs. CHANGELOG Security and Breaking rows, README secret-redaction section (its "Not covered" list no longer names
ToolMutatedarguments andToolBlockedreasons), CLAUDE.md Hooks row.Main code: +124 net lines (spec budget ~100). The rest is the
JsonSnapshotcut that Sail's round-1 MEDIUM asked for and the sixth log line found in pre-merge review.Pre-merge review (correctness, adversarial, coverage, design): attack sessions recovered no secret or 4+ char fragment through the logs or events; 45 hand mutants, all observable ones killed; ~105k repetitions of the new tests, 0 failures.
mvn -B clean verify javadoc:jar: 7875 tests run, 0 failures, 62 skipped (tests that need live provider keys); PMD, CPD, ArchUnit and coverage gates pass.🤖 Generated with Claude Code