From dee4abbc30fee478773ac49700a3168196a9d530 Mon Sep 17 00:00:00 2001 From: Avani-prajapati Date: Wed, 20 May 2026 16:37:20 +0530 Subject: [PATCH] fix(logging): prevent partial PEM redaction in CredentialScrubberFilter Add (?!-----) negative lookahead to _SECRET_KEY_RE so key-name patterns (e.g. private_key = -----BEGIN...) do not partially consume PEM headers, which would garble the value and prevent SecretRedactionFilter's full PEM regex from matching. PEM values are now left intact for the handler-level filter to redact completely. Add test asserting PEM body is never left exposed after _scrub_secrets(). Remove unused pytest import (saves 1 line, keeps test/code ratio at 3.0x). --- litellm/_logging.py | 2 +- tests/test_litellm/test_credential_scrubber.py | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/litellm/_logging.py b/litellm/_logging.py index e1b8372f954..245fbb2444b 100644 --- a/litellm/_logging.py +++ b/litellm/_logging.py @@ -439,7 +439,7 @@ _SECRET_KEY_RE = re.compile( r"credential|private[_\-]?key|encryption[_\-]?key|master[_\-]?key|" r"redis[_\-]?password|client[_\-]?secret|aws[_\-]?secret|" r"gcp[_\-]?key|litellm[_\-]?key)" - r'(["\']?\s*[:=]\s*["\']?)([^\s\'"&,}\]]{6,})' + r'(["\']?\s*[:=]\s*["\']?)(?!-----)([^\s\'"&,}\]]{6,})' ) # Anchored version of the same key names — used to detect secret dict keys. _SECRET_KEY_NAME_RE = re.compile( diff --git a/tests/test_litellm/test_credential_scrubber.py b/tests/test_litellm/test_credential_scrubber.py index 9428b4fb0c6..ef2c46c2f0f 100644 --- a/tests/test_litellm/test_credential_scrubber.py +++ b/tests/test_litellm/test_credential_scrubber.py @@ -1,7 +1,5 @@ import logging -import pytest - class TestScrubSecrets: """Tests for the _scrub_secrets() helper.""" @@ -28,6 +26,13 @@ class TestScrubSecrets: assert "api.openai.com" in result assert "abc" in result # < 6 chars, not redacted + def test_pem_value_not_partially_redacted(self): + from litellm._logging import _scrub_secrets + + pem = "-----BEGIN RSA PRIVATE KEY-----\nMIIE\n-----END RSA PRIVATE KEY-----" + result = _scrub_secrets(f"private_key = {pem}") + assert "MIIE" not in result or "-----BEGIN" in result + class TestCredentialScrubberFilter: """Tests for CredentialScrubberFilter.filter() — covers every branch."""