fix(llm-security): close OpenAI legacy key recall gap in pre-edit-secrets hook

Bare/unquoted legacy OpenAI keys (no label assignment, no Bearer prefix)
slipped past the pre-write secret-detection hook. Added a pattern anchored
on the T3BlbkFJ base64 "OpenAI" watermark (vendor-documented shape),
avoiding the collision-prone bare sk-+48alnum form. Failing tests first,
full suite green (2184/0/6).

The originally planned source for this fix — porting two entries from
commons' secret-egress.json — turned out to be a false premise: that file
is a byte-identical copy of this hook's own table, not a superset. The two
missing names existed only as prose in commons' conformance/manifest.json,
describing a different repo's (the guard's) unpublished Python table.
gcp-service-account-json was measured NOT to be a gap (already covered by
the existing PEM-block pattern); openai-api-key-legacy was the one real
gap, closed here with a locally-authored pattern rather than an invented
"port". Commons notified via coord-send that their secret-egress.json
(count: 18) is now stale.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PYJX35KLH3rpS6pi7LHj8u
This commit is contained in:
Kjell Tore Guttormsen 2026-08-11 13:43:27 +02:00
commit 088e45836c
2 changed files with 50 additions and 0 deletions

View file

@ -41,6 +41,12 @@ const SECRET_PATTERNS = [
{ name: 'Generic credential assignment', pattern: /(?:password|passwd|secret|token|api[_-]?key)\s*[=:]\s*['"][^'"]{8,}['"]/i },
{ name: 'Authorization header with token', pattern: /[Bb]earer [A-Za-z0-9\-._~+/]{20,}/ },
{ name: 'Database connection string', pattern: /(?:postgres|mysql|mongodb|redis):\/\/[^\s]+@[^\s]+/i },
// OpenAI legacy API key (pre-2024 sk-<48 chars> shape). Anchored on the
// T3BlbkFJ base64 "OpenAI" watermark embedded mid-token rather than a
// bare sk-+48alnum shape, which would collide with sk-ant-/sk-proj- and
// other unrelated sk-* tokens. Recall gap: bare/unquoted legacy keys
// (no label assignment, no Bearer prefix) previously slipped through.
{ name: 'OpenAI Legacy API Key', pattern: /\bsk-[A-Za-z0-9]{20}T3BlbkFJ[A-Za-z0-9]{20}\b/ },
// v7.8.3 #13 — three-part JWT (header.payload.signature, base64url). The
// 10-char part minimum keeps prose fragments (eyJabc.def.ghi) from tripping.
// Kept last so a Bearer-header context reports as 'Authorization header'.