fix(utils): redact credentials nested in extra_body on the verbose optional-params line

The "Final returned optional params" line printed whatever the caller nested inside
extra_body, so a credential tucked in there reached stdout in plaintext one line after
the request line that already redacts it.

The call site now runs redact_credentials_in_payload behind a guard reading both of
print_verbose's consumers, litellm.set_verbose and the LiteLLM logger's DEBUG level, so
the line prints in exactly the cases it did before and the walk costs nothing when
nothing would read it.
This commit is contained in:
mateo-berri 2026-09-03 02:53:50 -07:00
parent 0a62195db2
commit 912572bfa5
2 changed files with 80 additions and 1 deletions

View file

@ -544,6 +544,14 @@ def print_verbose(
pass
def _print_verbose_is_active() -> bool:
"""Whether print_verbose would reach either of its two consumers, so a call site can skip
building a payload nothing would read. _is_debugging_on() is not the same predicate: it reads
litellm._logging.set_verbose, while print_verbose's print reads litellm.set_verbose, and
assigning the documented litellm.set_verbose = True rebinds only the latter."""
return litellm.set_verbose is True or verbose_logger.isEnabledFor(logging.DEBUG)
####### CLIENT ###################
# make it easy to log if completion/embedding runs succeeded or failed + see what happened | Non-Blocking
def custom_llm_setup():
@ -4705,7 +4713,8 @@ def get_optional_params(
openai_params=list(DEFAULT_CHAT_COMPLETION_PARAM_VALUES.keys()),
additional_drop_params=additional_drop_params,
)
print_verbose(f"Final returned optional params: {optional_params}")
if _print_verbose_is_active():
print_verbose(f"Final returned optional params: {redact_credentials_in_payload(optional_params)}")
optional_params = _apply_openai_param_overrides(
optional_params=optional_params,
non_default_params=non_default_params,

View file

@ -5867,3 +5867,73 @@ class TestVerboseRequestLineRedaction:
assert "model='gpt-3.5-turbo'" in printed
assert "max_tokens=17" in printed
assert "temperature=0.25" in printed
class TestFinalOptionalParamsLineRedaction:
"""A verbose run echoes the fully built optional params too, and `extra_body` carries whatever the
caller nested inside it straight onto that line, so a credential tucked in there lands in a terminal
or a log drain in plaintext. It has to be redacted on both surfaces `print_verbose` writes to, and the
line has to keep printing on both, because `litellm.set_verbose` and the DEBUG logger are independent
switches and neither implies the other."""
FAKE_NESTED_KEY: Final = "sk-fake-lit6835-nested-0000000000"
def _complete(self, **kwargs) -> None:
litellm.completion(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "hello"}],
mock_response="hi",
**kwargs,
)
def _printed_line(self, capsys) -> str:
captured: Final = capsys.readouterr()
return "\n".join(
line for line in (captured.out + captured.err).splitlines() if "Final returned optional params" in line
)
def test_nested_credential_is_redacted_when_only_set_verbose_is_on(self, capsys, caplog, monkeypatch):
monkeypatch.setattr(litellm, "set_verbose", True)
with caplog.at_level(logging.WARNING, logger=verbose_logger.name):
capsys.readouterr()
self._complete(extra_body={"providers": [{"name": "openai", "api_key": self.FAKE_NESTED_KEY}]})
printed: Final = self._printed_line(capsys)
assert printed
assert self.FAKE_NESTED_KEY not in printed
assert "'api_key': 'REDACTED'" in printed
assert "'name': 'openai'" in printed
def test_line_still_reaches_the_logger_when_only_the_debug_logger_is_on(self, capsys, caplog, monkeypatch):
monkeypatch.setattr(litellm, "set_verbose", False)
with caplog.at_level(logging.DEBUG, logger=verbose_logger.name):
self._complete(extra_body={"providers": [{"name": "openai", "api_key": self.FAKE_NESTED_KEY}]})
logged: Final = "\n".join(
record.getMessage()
for record in caplog.records
if "Final returned optional params" in record.getMessage()
)
assert logged
assert self.FAKE_NESTED_KEY not in logged
assert "'name': 'openai'" in logged
def test_nothing_is_emitted_when_neither_verbose_switch_is_on(self, capsys, caplog, monkeypatch):
monkeypatch.setattr(litellm, "set_verbose", False)
with caplog.at_level(logging.WARNING, logger=verbose_logger.name):
capsys.readouterr()
self._complete(extra_body={"providers": [{"name": "openai", "api_key": self.FAKE_NESTED_KEY}]})
captured: Final = capsys.readouterr()
assert "Final returned optional params" not in captured.out + captured.err
assert self.FAKE_NESTED_KEY not in captured.out + captured.err
def test_ordinary_optional_params_still_reach_the_line(self, capsys, caplog, monkeypatch):
monkeypatch.setattr(litellm, "set_verbose", True)
with caplog.at_level(logging.WARNING, logger=verbose_logger.name):
capsys.readouterr()
self._complete(max_tokens=17, temperature=0.25)
printed: Final = self._printed_line(capsys)
assert "'max_tokens': 17" in printed
assert "'temperature': 0.25" in printed