Observed problem
lib/redact-patterns.ts openai.key (tier HIGH, "block") detects an OpenAI key only when the body is a contiguous alphanumeric run right after the prefix:
regex: /\b(sk-(?:proj-)?[A-Za-z0-9]{32,})\b/,
Modern OpenAI keys are no longer pure-alphanumeric. Project / service-account / admin keys (sk-proj-, sk-svcacct-, sk-admin-) use a base64url-style body that contains - and _ — the same charset secret scanners (gitleaks, trufflehog, GitHub secret scanning) use for OpenAI. Because [A-Za-z0-9]{32,} stops at the first -/_, these keys never reach the 32-char run and produce no finding at all — a HIGH-tier credential fails open straight through the redaction gate used by /spec, /ship, /cso, and /document-*.
The sibling anthropic.key pattern in the same file already allows separators (/\b(sk-ant-[A-Za-z0-9_\-]{20,})\b/); openai.key is the inconsistent one.
Current behavior on main (c43c850)
Scanning realistic prefixed keys returns zero findings:
$ # via lib/redact-engine scan()
MISSED sk-proj-Ab12_Cd34-Ef56Gh78Ij90Kl12Mn34Op56Qr78St90Uv -> findings: NONE
MISSED sk-svcacct-abc_def-ghijklmnopqrstuvwxyz0123456789ABCDEF -> findings: NONE
DETECTED sk-proj-aaaaaaaaaa...(40 contiguous, the only shape the test covers)
test/redact-engine.test.ts:38 only exercises "sk-proj-" + "a".repeat(40) (contiguous), so the gap is untested.
Expected behavior
A live sk-proj- / sk-svcacct- / sk-admin- key with -/_ in its body should produce a HIGH openai.key finding and block, like every other genuinely-secret credential.
Duplicate search performed
Candidate fix shape
Widen the body charset to [A-Za-z0-9_\-] only on the prefixed form, keeping the bare sk- legacy path narrow so it doesn't start matching kebab/snake identifiers:
regex: /\b(sk-(?:proj|svcacct|admin)-[A-Za-z0-9_\-]{32,}|sk-[A-Za-z0-9]{32,})\b/,
Plus a regression test for the separator-bearing prefixed forms. Single bounded quantifier per alternative — linear-time, passes redact-pattern-lint.
Observed problem
lib/redact-patterns.tsopenai.key(tier HIGH, "block") detects an OpenAI key only when the body is a contiguous alphanumeric run right after the prefix:Modern OpenAI keys are no longer pure-alphanumeric. Project / service-account / admin keys (
sk-proj-,sk-svcacct-,sk-admin-) use a base64url-style body that contains-and_— the same charset secret scanners (gitleaks, trufflehog, GitHub secret scanning) use for OpenAI. Because[A-Za-z0-9]{32,}stops at the first-/_, these keys never reach the 32-char run and produce no finding at all — a HIGH-tier credential fails open straight through the redaction gate used by/spec,/ship,/cso, and/document-*.The sibling
anthropic.keypattern in the same file already allows separators (/\b(sk-ant-[A-Za-z0-9_\-]{20,})\b/);openai.keyis the inconsistent one.Current behavior on
main(c43c850)Scanning realistic prefixed keys returns zero findings:
test/redact-engine.test.ts:38only exercises"sk-proj-" + "a".repeat(40)(contiguous), so the gap is untested.Expected behavior
A live
sk-proj-/sk-svcacct-/sk-admin-key with-/_in its body should produce a HIGHopenai.keyfinding and block, like every other genuinely-secret credential.Duplicate search performed
lib/redact-*: only fix(redact): invalid --max-bytes must not disable the fail-closed oversize guard #1825 (mine —bin/gstack-redact--max-bytesCLI validation inredact-engine.ts; different file, different bug). No collision.redact-patterns.tshistory: only touched by the original v1.53.0.0 feature PR v1.53.0.0 feat: smarter redaction — PII/secrets/legal guard across /spec, /ship, /cso, /document-* #1797 (merged). No community PR open against it.sk-proj, "openai key", redact pattern: no existing issue or PR.Candidate fix shape
Widen the body charset to
[A-Za-z0-9_\-]only on the prefixed form, keeping the baresk-legacy path narrow so it doesn't start matching kebab/snake identifiers:Plus a regression test for the separator-bearing prefixed forms. Single bounded quantifier per alternative — linear-time, passes
redact-pattern-lint.