You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
security: RedactString misses secrets split by a NUL or ESC #969
Windows 10. Static review of internal/redaction; no provider call required.
Steps to reproduce
Take a key that the shape matcher already catches, e.g. sk-ant-api03-abcdefghijklmnopqrstuvwxyz0123456789ABCD.
Call RedactString on the unsplit value → it redacts.
Insert a NUL (or ESC) in the body, e.g. sk-ant-api03-\x00abcdefghijklmnopqrstuvwxyz0123456789ABCD.
Call RedactString again → no match.
Strip the control byte from the result → the two fragments rejoin into the original secret. RedactString (internal/redaction/redaction.go) matches shapes on the raw string. It never strips C0/C1 bytes first. There is no split-case test in the package.
This is the AGENTS.md “normalize before matching” gap: redacting by shape and then (or never) stripping control bytes lets a split credential pass as two fragments and be rejoined on the way out. An unsplit pass is not evidence.
Expected behavior
The split form is redacted the same as the unsplit form. A regression test fails on current main for the NUL-split case.
Actual behavior
Unsplit: redacted. NUL-split: secret survives. After dropping the NUL, the original key is visible again.
Relevant logs, screenshots, or error messages
Strip/normalize control bytes first, then match. Add a split-case test (NUL and ESC). Do not treat an unsplit-only test as coverage.
Decision on the two PRs for this: #1067 is the fix. Disclosure: it's mine. It's the one that holds on the measured cases. On the same inputs it exposes no usable credential, and jatmn has approved it; its known limit (the tail of a key whose front part is complete on its own) is stated in its description. The details on #1075, including the two cases that still leak a usable GitHub token or JWT and the two quadratic paths, are in my last review there.
@cairn-intern thank you for #1075. It found a real improvement over main that mine doesn't have (two AWS keys glued end to end), and that's worth a separate small PR if you want to carry it over.
Activity
fix(redaction): strip C0/C1 bytes before shape matching
Resolve secret boundary incrementally and bound test scaling
Format redaction.go with go fmt
Consume split credential bytes across valid gaps and fail closed
Track OpenAI kebab state incrementally and assert exact secret redaction
Eliminate quadratic validation on non-OpenAI shapes and remove unused…
Resolve review feedback for control-split secret redaction
Remove unreachable redaction validation and restore formatting checks.
Redact neighboring JWTs without truncating independent-token detection.
Keep incomplete credential prefixes inside valid redaction candidates.
Vasanthdev2004 commentedon Sep 26, 2026
Decision on the two PRs for this: #1067 is the fix. Disclosure: it's mine. It's the one that holds on the measured cases. On the same inputs it exposes no usable credential, and jatmn has approved it; its known limit (the tail of a key whose front part is complete on its own) is stated in its description. The details on #1075, including the two cases that still leak a usable GitHub token or JWT and the two quadratic paths, are in my last review there.
@cairn-intern thank you for #1075. It found a real improvement over main that mine doesn't have (two AWS keys glued end to end), and that's worth a separate small PR if you want to carry it over.
fix(redaction): redact adjacent AWS keys glued end to end (#1095)
fix(redaction): redact credentials split by an invisible character (T…