Follow-up from the independent review of #360 (see its final review comment).
Every capturer runs redactSecrets(JSON.stringify(entry)) (src/hooks/capture.ts:177, the codex/cursor/hermes hooks, and src/mcp/cowork-ingest.ts since #359). tool_input / tool_response are themselves JSON.stringify-ed first (src/hooks/capture.ts:134-135), so the redactor sees doubly-nested JSON text. #360 keeps the common single-level trailing-escape valid (maskBeforeQuote in src/hooks/shared/redact.ts), but a secret that is purely backslashes or ends in a literal " under that double nesting still produces an unparseable line, which the session queue stores as an opaque raw_message row. Pre-existing on main; identical before #360.
Redacting serialized text cannot be nesting-correct in general (the inner escape \" is \\\" at depth 2, 7 chars at depth 3). The sound fix is to redact the string fields (content, tool_input, tool_response) before serialization in each capturer, then serialize once. Regression shapes to keep: password=\\, password=abc", token=xy\z\, nested through JSON.stringify({ content: JSON.stringify(secret) }).
Also from CodeRabbit on #360 (same area, separate behaviour change): quote-aware tokenization so password="two words" masks the whole quoted value; today the rule stops at whitespace.
Follow-up from the independent review of #360 (see its final review comment).
Every capturer runs
redactSecrets(JSON.stringify(entry))(src/hooks/capture.ts:177, the codex/cursor/hermes hooks, andsrc/mcp/cowork-ingest.tssince #359).tool_input/tool_responseare themselvesJSON.stringify-ed first (src/hooks/capture.ts:134-135), so the redactor sees doubly-nested JSON text. #360 keeps the common single-level trailing-escape valid (maskBeforeQuoteinsrc/hooks/shared/redact.ts), but a secret that is purely backslashes or ends in a literal"under that double nesting still produces an unparseable line, which the session queue stores as an opaqueraw_messagerow. Pre-existing on main; identical before #360.Redacting serialized text cannot be nesting-correct in general (the inner escape
\"is\\\"at depth 2, 7 chars at depth 3). The sound fix is to redact the string fields (content,tool_input,tool_response) before serialization in each capturer, then serialize once. Regression shapes to keep:password=\\,password=abc",token=xy\z\, nested throughJSON.stringify({ content: JSON.stringify(secret) }).Also from CodeRabbit on #360 (same area, separate behaviour change): quote-aware tokenization so
password="two words"masks the whole quoted value; today the rule stops at whitespace.