mask_secrets misses the single most common structured shape a pasted credential takes — a JSON / quoted key — so it leaks into the capture buffer that becomes a committed session page and the append-only audit log.
where — src/vouch/secrets.py:40-44:
_ASSIGNMENT = re.compile(
r"(?i)\b(api[_-]?key|secret|token|password|passwd|pwd|access[_-]?key)\b"
r"(\s*[:=]\s*)"
r"[\"']?[^\s\"']{6,}[\"']?"
)
The docstring/comment says it covers "key=value / key: value for sensitive-looking names — mask the value". But for "password": "hunter2secret" the name matches password, then the very next character is the key's closing quote ", while the separator group expects optional whitespace then :/=. The quote sits between them, so the match fails. A value that also isn't a recognized token format (a plain password, a short/custom key) then has no fallback and slips whole.
verified — regex and real pipeline:
mask | "password=hunter2secret" -> password=[redacted-secret]
mask | "password: hunter2secret" -> password: [redacted-secret]
LEAK | '"password": "hunter2secret"' -> unchanged
LEAK | "'api_key': 'abcdefghij'" -> unchanged
Driving the real capture.observe path with {"password": "hunter2supersecret"} in an observation, the secret lands verbatim in .vouch/captures/<sess>.jsonl today — the gitignored buffer that rolls into a committed session page + audit log. That is exactly the file family vouch itself writes (.claude/settings.json via the install-adapter json_merge, config.yaml).
fix — allow an optional closing quote after the key name, folded into the captured separator group so the quote is preserved:
masks the leaking JSON/quoted-key forms ("password": [redacted-secret]), keeps every currently-working case masking, and adds no false positives (no-separator, sub-6-char value, quote-without-separator all stay untouched). happy to send it.
mask_secretsmisses the single most common structured shape a pasted credential takes — a JSON / quoted key — so it leaks into the capture buffer that becomes a committed session page and the append-only audit log.where —
src/vouch/secrets.py:40-44:The docstring/comment says it covers "key=value / key: value for sensitive-looking names — mask the value". But for
"password": "hunter2secret"the name matchespassword, then the very next character is the key's closing quote", while the separator group expects optional whitespace then:/=. The quote sits between them, so the match fails. A value that also isn't a recognized token format (a plain password, a short/custom key) then has no fallback and slips whole.verified — regex and real pipeline:
Driving the real
capture.observepath with{"password": "hunter2supersecret"}in an observation, the secret lands verbatim in.vouch/captures/<sess>.jsonltoday — the gitignored buffer that rolls into a committed session page + audit log. That is exactly the file family vouch itself writes (.claude/settings.jsonvia the install-adapter json_merge,config.yaml).fix — allow an optional closing quote after the key name, folded into the captured separator group so the quote is preserved:
r"([\"']?\s*[:=]\s*)"masks the leaking JSON/quoted-key forms (
"password": [redacted-secret]), keeps every currently-working case masking, and adds no false positives (no-separator, sub-6-char value, quote-without-separator all stay untouched). happy to send it.