Skip to content

gstack-redact: openai.key misses modern sk-proj-/sk-svcacct-/sk-admin- keys (separators in body) — HIGH credential fails open #1868

@jbetala7

Description

@jbetala7

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions