Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions lib/redact-patterns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,14 @@ export const PATTERNS: RedactPattern[] = [
id: "openai.key",
tier: "HIGH",
category: "secret",
description: "OpenAI API key (incl. sk-proj-)",
regex: /\b(sk-(?:proj-)?[A-Za-z0-9]{32,})\b/,
description: "OpenAI API key (legacy sk- + project/service/admin keys)",
// Two forms. Legacy keys are bare `sk-` + a contiguous alphanumeric run.
// Modern keys carry a `sk-proj-` / `sk-svcacct-` / `sk-admin-` prefix and a
// base64url-style body that includes `-` and `_` (the same charset the
// sibling `anthropic.key` already allows). The body charset is widened only
// on the prefixed form so the bare `sk-` path keeps its narrow alnum match
// and does not start matching kebab/snake identifiers that begin with `sk-`.
regex: /\b(sk-(?:proj|svcacct|admin)-[A-Za-z0-9_\-]{32,}|sk-[A-Za-z0-9]{32,})\b/,
},
{
id: "sendgrid.key",
Expand Down
14 changes: 14 additions & 0 deletions test/redact-engine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,20 @@ describe("HIGH credential patterns", () => {
expect(ids(`random ${tok} here`)).not.toContain("twilio.auth_token");
});

test("openai.key flags modern prefixed keys whose body carries -/_ separators", () => {
// Regression: the legacy regex required a contiguous [A-Za-z0-9] run right
// after the prefix, so real `sk-proj-`/`sk-svcacct-`/`sk-admin-` keys (whose
// base64url body contains `-` and `_`) slipped through with NO finding — a
// HIGH credential failing OPEN past the redaction gate.
expect(ids("OPENAI_API_KEY=sk-proj-Ab12_Cd34-Ef56Gh78Ij90Kl12Mn34Op56Qr78St90Uv")).toContain("openai.key");
expect(ids("sk-svcacct-abc_def-ghijklmnopqrstuvwxyz0123456789ABCDEF")).toContain("openai.key");
expect(ids("sk-admin-AAA_bbb-CCCdddEEEfffGGGhhhIIIjjjKKKlllMMMnnn")).toContain("openai.key");
// Legacy bare `sk-` + contiguous alnum still flagged.
expect(ids("sk-" + "B".repeat(48))).toContain("openai.key");
// FP guard: a short `sk-` kebab identifier is not a key.
expect(ids("ran the sk-mydata step")).not.toContain("openai.key");
});

test("db.url_with_password flags real password, skips placeholder/env-var", () => {
expect(ids("postgres://user:s3cretP@ss@db.example.com/app")).toContain("db.url_with_password");
expect(ids("postgres://user:${DB_PASSWORD}@host/app")).not.toContain("db.url_with_password");
Expand Down
Loading