diff --git a/src/lib/local/query.test.ts b/src/lib/local/query.test.ts index 4eef0ba..1bd1e1a 100644 --- a/src/lib/local/query.test.ts +++ b/src/lib/local/query.test.ts @@ -410,4 +410,20 @@ describe("searchFileContent", () => { expect(searchFileContent("needlecomparison", {}, db)[0]!.lineText).toBe(comparisonLine); expect(searchFileContent("needletype", {}, db)[0]!.lineText).toBe(typeLine); }); + + test("redacts DB_PASS assignments and Basic authorization credentials from emitted matches", () => { + const value = ["synthetic", "review", "value", "731"].join("-"); + setup({ + "db-config.txt": `needledb DB_PASS=${value}`, + "request.txt": `needlebasic Authorization: Basic ${value}`, + }); + + const dbPassHit = searchFileContent("needledb", {}, db)[0]!; + expect(dbPassHit.lineText.includes(value)).toBe(false); + expect(dbPassHit.lineText).toBe("needledb DB_PASS=[REDACTED]"); + + const basicHit = searchFileContent("needlebasic", {}, db)[0]!; + expect(basicHit.lineText.includes(value)).toBe(false); + expect(basicHit.lineText).toBe("needlebasic Authorization: Basic [REDACTED]"); + }); }); diff --git a/src/lib/redaction.test.ts b/src/lib/redaction.test.ts index 7e9f196..0d44602 100644 --- a/src/lib/redaction.test.ts +++ b/src/lib/redaction.test.ts @@ -50,6 +50,20 @@ describe("redactCredentialBearingText", () => { ); }); + test("redacts DB_PASS assignments and Basic authorization credentials", () => { + const value = ["synthetic", "review", "value", "731"].join("-"); + + expect(redactCredentialBearingText(`DB_PASS=${value}`)).toBe( + `DB_PASS=${REDACTION_PLACEHOLDER}`, + ); + expect(redactCredentialBearingText(`Authorization: Basic ${value}`)).toBe( + `Authorization: Basic ${REDACTION_PLACEHOLDER}`, + ); + expect(redactCredentialBearingText(`authorization: basic ${value}`)).toBe( + `authorization: basic ${REDACTION_PLACEHOLDER}`, + ); + }); + test("redacts common standalone credential token shapes", () => { const values = [ ["sk-", "synthetic_token_123456789"].join(""), diff --git a/src/lib/redaction.ts b/src/lib/redaction.ts index 3897437..25dbede 100644 --- a/src/lib/redaction.ts +++ b/src/lib/redaction.ts @@ -3,7 +3,7 @@ import type { SearchResult } from "../types/index.js"; export const REDACTION_PLACEHOLDER = "[REDACTED]"; const SENSITIVE_KEY_SOURCE = - String.raw`\b[a-z0-9_-]*(?:api[_-]?key|access[_-]?key|secret(?:[_-]?key)?|client[_-]?secret|(?:auth|access|refresh)[_-]?token|token|password|passwd|pwd|passphrase|private[_-]?key)\b`; + String.raw`\b[a-z0-9_-]*(?:api[_-]?key|access[_-]?key|secret(?:[_-]?key)?|client[_-]?secret|(?:auth|access|refresh)[_-]?token|token|password|passwd|pwd|pass|passphrase|private[_-]?key)\b`; const SENSITIVE_EQUALS_ASSIGNMENT_PATTERN = new RegExp( `(${SENSITIVE_KEY_SOURCE}["'\\x60]?[\\s]*=[\\s]*)(?![=>])(["'\\x60]?).*$`, @@ -25,7 +25,7 @@ const SENSITIVE_ASSIGNMENT_PATTERNS = [ ] as const; const CREDENTIAL_URL_PATTERN = /([a-z][a-z0-9+.-]*:\/\/[^/\s:@]+:)([^@\s/]+)(@)/gi; -const BEARER_TOKEN_PATTERN = /(\bBearer\s+)[a-z0-9._~+/-]{8,}=*/gi; +const AUTHORIZATION_CREDENTIAL_PATTERN = /(\b(?:Bearer|Basic)\s+)[a-z0-9._~+/-]{8,}=*/gi; const INLINE_CREDENTIAL_PATTERNS: readonly RegExp[] = [ /\bsk-[a-z0-9_-]{10,}\b/gi, @@ -57,7 +57,7 @@ export function redactCredentialBearingText(text: string): string { `${prefix}${REDACTION_PLACEHOLDER}${suffix}`, ); redacted = redacted.replace( - BEARER_TOKEN_PATTERN, + AUTHORIZATION_CREDENTIAL_PATTERN, (_match: string, prefix: string) => `${prefix}${REDACTION_PLACEHOLDER}`, );