diff --git a/enterprise/litellm_enterprise/enterprise_callbacks/secret_detection.py b/enterprise/litellm_enterprise/enterprise_callbacks/secret_detection.py index f726dd390b2..85366fd7dcc 100644 --- a/enterprise/litellm_enterprise/enterprise_callbacks/secret_detection.py +++ b/enterprise/litellm_enterprise/enterprise_callbacks/secret_detection.py @@ -503,12 +503,7 @@ def _parseable_lines(text: str) -> Iterator[str]: def _quoted_assignments(text: str) -> tuple[str, ...]: parser: Final = configparser.ConfigParser(interpolation=None) parser.optionxform = str # pyright: ignore[reportAttributeAccessIssue] # configparser types optionxform as a method - body: Final = "\n".join(_parseable_lines(text)) - try: - parser.read_string(f"[{_CONFIG_SECTION}]\n{body}") - except (configparser.Error, UnicodeDecodeError): - return () - + parser.read_string(f"[{_CONFIG_SECTION}]\n" + "\n".join(_parseable_lines(text))) return tuple( f'{key} = "{value}"' for section in parser 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 3c90fdad91a..3e273affa46 100644 --- a/tests/test_litellm/enterprise/enterprise_callbacks/test_secret_detection.py +++ b/tests/test_litellm/enterprise/enterprise_callbacks/test_secret_detection.py @@ -390,6 +390,24 @@ def test_scan_message_reads_a_config_with_a_broken_section_header(content): assert "Zx4Kp9Lm2Qr7Ns3Vt" not in guardrail.redact_text(content) +@pytest.mark.parametrize( + "content", + [ + "=orphan\npassword = Zx4Kp9Lm2Qr7Ns3Vt\n", + " indented before any key\npassword = Zx4Kp9Lm2Qr7Ns3Vt\n", + "greeting = %(name)s\npassword = Zx4Kp9Lm2Qr7Ns3Vt\n", + "token = a\x00b\npassword = Zx4Kp9Lm2Qr7Ns3Vt\n", + ], + ids=["empty-key", "leading-continuation", "interpolation", "nul-byte"], +) +def test_scan_message_reads_lines_that_a_stock_ini_parser_rejects(content): + """The parser has no error fallback, so every line shape must be filtered or + accepted before it reaches configparser, or one odd line would 500 the request.""" + guardrail = _guardrail() + + assert "Zx4Kp9Lm2Qr7Ns3Vt" not in guardrail.redact_text(content) + + def test_scan_message_reads_a_config_that_repeats_a_section(): """A pasted ini can name the same section twice, and refusing to parse it would drop every assignment in the message, not just the repeated one."""