mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-25 01:02:15 +00:00
fix(logging): scrub non-primitive tuple args (e.g. dicts) passed via %s (CWE-312)
Previously, only string elements in a log record's tuple args were scrubbed.
A dict like {"api_key": "sk-..."} passed as `logger.debug("cfg: %s", config)`
would reach any custom handler attached to LiteLLM loggers untouched.
Now any non-primitive tuple element (i.e. not bool/int/float/None) is
converted to its string repr and scrubbed before handlers see the record,
closing the parameterised-log bypass identified by Veria AI.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
0e092468c3
commit
b7151d9b95
2 changed files with 13 additions and 2 deletions
|
|
@ -478,7 +478,11 @@ class CredentialScrubberFilter(logging.Filter):
|
|||
}
|
||||
elif isinstance(record.args, tuple):
|
||||
record.args = tuple(
|
||||
_scrub_secrets(str(a)) if isinstance(a, str) else a
|
||||
(
|
||||
_scrub_secrets(str(a))
|
||||
if not isinstance(a, (bool, int, float, type(None)))
|
||||
else a
|
||||
)
|
||||
for a in record.args
|
||||
)
|
||||
if record.exc_info and record.exc_info[1] is not None:
|
||||
|
|
|
|||
|
|
@ -113,7 +113,13 @@ class TestCredentialScrubberFilter:
|
|||
|
||||
f = CredentialScrubberFilter()
|
||||
record = self._make_record(
|
||||
"vals=%s %s %s", (42, None, "api_key=sk-secret123456789")
|
||||
"vals=%s %s %s %s",
|
||||
(
|
||||
42,
|
||||
None,
|
||||
"api_key=sk-secret123456789",
|
||||
{"api_key": "sk-dictval12345678901"},
|
||||
),
|
||||
)
|
||||
f.filter(record)
|
||||
args = record.args
|
||||
|
|
@ -121,6 +127,7 @@ class TestCredentialScrubberFilter:
|
|||
assert args[0] == 42
|
||||
assert args[1] is None
|
||||
assert "sk-secret123456789" not in str(args[2])
|
||||
assert "sk-dictval12345678901" not in str(args[3])
|
||||
|
||||
def test_no_args_no_crash(self):
|
||||
# Branch: record.args is falsy (empty tuple)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue