fix(extract): also redact opaque Bearer tokens; guard against over-redaction

Follow-up to #4566. Adds an opaque (non-JWT) `Bearer <token>` shape to the
credential redactor so `Authorization: Bearer <opaque>` is redacted (the JWT form
was already caught by the eyJ pattern); the word "Bearer" is kept, only the token
is replaced. Adds an over-redaction regression test proving a 40-char git SHA, a
sha256 digest and a UUID pass through untouched, so the redactor never mangles the
ordinary high-entropy identifiers that appear in real rationale labels.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
safishamsiandClaude Opus 4.8 committed 2026-10-20 10:54:35 +01:00
1 parent 3d20f14d38
commit 374adfadab
2 files changed
+23

No files matched your search

+1
View File
@@ -404,6 +404,7 @@ _SECRET_SHAPE_RE = re.compile(
r"|\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{20,}"
r"|\bAIza[0-9A-Za-z_-]{35}\b"
r"|\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}"
r"|(?<=\bBearer )[A-Za-z0-9._~+/=-]{16,}"
r"|(?<=://)[^\s/:@]+:[^\s/@]+(?=@)"
)
+22
View File
@@ -490,3 +490,25 @@ def test_redact_secrets_leaves_plain_text_and_none():
assert redact_secrets("use chunked processing; see https://example.com/a/b") == "use chunked processing; see https://example.com/a/b"
assert redact_secrets(None) == ""
assert redact_secrets("") == ""
def test_redact_secrets_opaque_bearer_token():
# An opaque (non-JWT) Bearer token is redacted; the word "Bearer" is kept.
from graphify.security import redact_secrets
out = redact_secrets("Authorization: Bearer abcDEF123456ghiJKL789mnop")
assert "abcDEF123456ghiJKL789mnop" not in out
assert out == "Authorization: Bearer [redacted]"
def test_redact_secrets_does_not_mangle_hashes_and_ids():
# Over-redaction guard: a credential-redactor that mangled ordinary
# high-entropy identifiers would corrupt real rationale labels. A git SHA,
# a sha256 digest and a UUID must pass through untouched.
from graphify.security import redact_secrets
for benign in (
"see commit 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b for context",
"digest sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"run id 550e8400-e29b-41d4-a716-446655440000 completed",
"class AkiaConfigProvider implements Provider",
):
assert redact_secrets(benign) == benign, benign