From 802c05904cea81d89eac0d886d044576ada1375c Mon Sep 17 00:00:00 2001 From: yucheng Date: Fri, 11 Sep 2026 22:11:09 +0000 Subject: [PATCH] fix(hide-secrets): keep spaced assignments in scope when shell text follows the value Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../enterprise_callbacks/secret_detection.py | 9 +++++++-- .../enterprise_callbacks/test_secret_detection.py | 6 ++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/enterprise/litellm_enterprise/enterprise_callbacks/secret_detection.py b/enterprise/litellm_enterprise/enterprise_callbacks/secret_detection.py index bd03e278679..8fee444c1d0 100644 --- a/enterprise/litellm_enterprise/enterprise_callbacks/secret_detection.py +++ b/enterprise/litellm_enterprise/enterprise_callbacks/secret_detection.py @@ -455,6 +455,8 @@ _SHELL_ASSIGNMENT: Final = re.compile(r"(?P[^\s\[#;:=](?:[^:=]*[^\s:=])?)=( _SHELL_OPERATORS: Final = ";&|" +_SHELL_TRAILER: Final = re.compile(r"\\|#.*|\S+=\S*") + _SCAN_SUFFIX: Final = ".py" @@ -509,9 +511,12 @@ def _parseable_lines(text: str) -> Iterator[str]: def _lone_value(line: str) -> str | None: tokens: Final = line.split() - if not tokens or '"' in tokens[0] or (len(tokens) > 1 and not tokens[1].startswith("#")): + if not tokens or '"' in tokens[0]: return None - return tokens[0].rstrip(_SHELL_OPERATORS) + value: Final = tokens[0].rstrip(_SHELL_OPERATORS) + if len(tokens) == 1 or value != tokens[0] or _SHELL_TRAILER.fullmatch(tokens[1]) is not None: + return value + return None def _quoted_assignments(text: str) -> tuple[str, ...]: diff --git a/tests/test_litellm/enterprise/enterprise_callbacks/test_secret_detection.py b/tests/test_litellm/enterprise/enterprise_callbacks/test_secret_detection.py index ae1693adf1e..068cf5d4c89 100644 --- a/tests/test_litellm/enterprise/enterprise_callbacks/test_secret_detection.py +++ b/tests/test_litellm/enterprise/enterprise_callbacks/test_secret_detection.py @@ -123,6 +123,9 @@ def test_scan_message_preserves_quoted_benign_identifiers(): ("DB_PASSWORD=Zx4Kp9Lm2Qr7Ns3Vt > setup.log", "Zx4Kp9Lm2Qr7Ns3Vt"), ("docker run -e DB_PASSWORD=Zx4Kp9Lm2Qr7Ns3Vt --name app postgres", "Zx4Kp9Lm2Qr7Ns3Vt"), ("password=correcthorsebattery please", "correcthorsebattery"), + ("DB_PASSWORD = Zx4Kp9Lm2Qr7Ns3Vt; systemctl restart app", "Zx4Kp9Lm2Qr7Ns3Vt"), + ("DB_PASSWORD = Zx4Kp9Lm2Qr7Ns3Vt \\", "Zx4Kp9Lm2Qr7Ns3Vt"), + ("DB_PASSWORD = Zx4Kp9Lm2Qr7Ns3Vt DB_HOST=db.internal", "Zx4Kp9Lm2Qr7Ns3Vt"), ], ids=[ "env-password", @@ -159,6 +162,9 @@ def test_scan_message_preserves_quoted_benign_identifiers(): "redirect-after-the-value", "docker-flag-after-the-value", "prose-after-a-shell-assignment", + "spaced-assignment-then-a-shell-command", + "spaced-assignment-then-a-line-continuation", + "spaced-assignment-then-a-second-assignment", ], ) def test_scan_message_redacts_credentials_assigned_to_credential_keys(content, secret):