From 374adfadabd368b76eb679aaae53107385f6a371 Mon Sep 17 00:00:00 2001 From: safishamsi Date: Tue, 20 Oct 2026 10:54:35 +0100 Subject: [PATCH] fix(extract): also redact opaque Bearer tokens; guard against over-redaction Follow-up to #4566. Adds an opaque (non-JWT) `Bearer ` shape to the credential redactor so `Authorization: Bearer ` 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 --- graphify/security.py | 1 + tests/test_security.py | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/graphify/security.py b/graphify/security.py index 1b6b80fb5..a2361171a 100644 --- a/graphify/security.py +++ b/graphify/security.py @@ -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/@]+(?=@)" ) diff --git a/tests/test_security.py b/tests/test_security.py index eb87b38bc..b0729acdd 100644 --- a/tests/test_security.py +++ b/tests/test_security.py @@ -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