Bearer token redaction regex fails on tokens ending with = or .
Severity: Medium
File: src/cain_agent/redact.py:108
The bearer token pattern uses \b (word boundary) after a character class that includes = and ., both of which are non-word characters:
RedactPattern(
name="bearer",
pattern=r"(?i)(Bearer\s+)([A-Za-z0-9_\-\.=]{20,})\b",
),
A \b matches between a word character ([A-Za-z0-9_]) and a non-word character. When the token ends with = or . (common in base64-padded or JWT-style tokens), the last character is already non-word, and the character after it (space, newline, or end-of-string) is also non-word — so no word boundary exists and the regex fails to match. For example, Bearer eyJhbGciOi.eyJzdWIi.signature== would not be redacted.
Why it matters
Base64-padded bearer tokens ending with = are common in real-world API responses. The redaction system silently passes them through, leaving credentials exposed in logs, findings, and reports — violating the data trust boundary documented in DESIGN section 3.2.
Bearer token redaction regex fails on tokens ending with
=or.Severity: Medium
File:
src/cain_agent/redact.py:108The bearer token pattern uses
\b(word boundary) after a character class that includes=and., both of which are non-word characters:A
\bmatches between a word character ([A-Za-z0-9_]) and a non-word character. When the token ends with=or.(common in base64-padded or JWT-style tokens), the last character is already non-word, and the character after it (space, newline, or end-of-string) is also non-word — so no word boundary exists and the regex fails to match. For example,Bearer eyJhbGciOi.eyJzdWIi.signature==would not be redacted.Why it matters
Base64-padded bearer tokens ending with
=are common in real-world API responses. The redaction system silently passes them through, leaving credentials exposed in logs, findings, and reports — violating the data trust boundary documented in DESIGN section 3.2.