mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-06 02:48:13 +00:00
refactor(proxy): always redact credential-named fields in stored spend-log payloads
This commit is contained in:
parent
8f46ffc942
commit
9ffc144f2a
2 changed files with 12 additions and 14 deletions
|
|
@ -1095,16 +1095,14 @@ def _sanitize_request_body_for_spend_logs_payload(
|
|||
request_body: Mapping[str, object],
|
||||
visited: set | None = None,
|
||||
max_string_length_prompt_in_db: int | None = None,
|
||||
redact_credentials: bool = False,
|
||||
) -> dict:
|
||||
"""
|
||||
Recursively sanitize request body to prevent logging large base64 strings or other large values.
|
||||
Truncates strings longer than MAX_STRING_LENGTH_PROMPT_IN_DB characters and handles nested dictionaries.
|
||||
|
||||
At every nesting level, also strips keys listed in _SENSITIVE_REQUEST_BODY_KEYS (e.g. secret_fields,
|
||||
which holds raw HTTP headers including Authorization tokens). With ``redact_credentials``, string
|
||||
values under keys SensitiveDataMasker classifies as credentials are replaced with
|
||||
REDACTED_BY_LITELM_STRING.
|
||||
which holds raw HTTP headers including Authorization tokens), and replaces string values under keys
|
||||
SensitiveDataMasker classifies as credentials with REDACTED_BY_LITELM_STRING.
|
||||
"""
|
||||
from litellm.constants import (
|
||||
LITELLM_TRUNCATED_PAYLOAD_FIELD,
|
||||
|
|
@ -1124,9 +1122,7 @@ def _sanitize_request_body_for_spend_logs_payload(
|
|||
|
||||
def _sanitize_value(value: object) -> object:
|
||||
if isinstance(value, Mapping):
|
||||
return _sanitize_request_body_for_spend_logs_payload(
|
||||
value, visited, max_string_length_prompt_in_db, redact_credentials
|
||||
)
|
||||
return _sanitize_request_body_for_spend_logs_payload(value, visited, max_string_length_prompt_in_db)
|
||||
elif isinstance(value, list):
|
||||
return [_sanitize_value(item) for item in value]
|
||||
elif isinstance(value, str):
|
||||
|
|
@ -1164,7 +1160,7 @@ def _sanitize_request_body_for_spend_logs_payload(
|
|||
return value
|
||||
|
||||
return {
|
||||
k: REDACTED_BY_LITELM_STRING if redact_credentials and _is_request_body_credential(k, v) else _sanitize_value(v)
|
||||
k: REDACTED_BY_LITELM_STRING if _is_request_body_credential(k, v) else _sanitize_value(v)
|
||||
for k, v in request_body.items()
|
||||
if k not in _SENSITIVE_REQUEST_BODY_KEYS
|
||||
}
|
||||
|
|
@ -1582,7 +1578,7 @@ def _get_proxy_server_request_for_spend_logs_payload(
|
|||
_request_body = _convert_mapping_to_json_serializable(without_classifier_audit(_request_body))
|
||||
perform_redaction(model_call_details=_request_body, result=None)
|
||||
|
||||
_request_body = _sanitize_request_body_for_spend_logs_payload(_request_body, redact_credentials=True)
|
||||
_request_body = _sanitize_request_body_for_spend_logs_payload(_request_body)
|
||||
_request_body_json_str: Final = safe_dumps(_request_body)
|
||||
if LITELLM_TRUNCATED_PAYLOAD_FIELD in _request_body_json_str:
|
||||
verbose_proxy_logger.info(
|
||||
|
|
|
|||
|
|
@ -612,7 +612,7 @@ def test_sanitize_request_body_for_spend_logs_payload_mixed_types():
|
|||
request_body = {
|
||||
"text": long_string,
|
||||
"number": 42,
|
||||
"nested": {"list": ["short", long_string], "dict": {"key": long_string}},
|
||||
"nested": {"list": ["short", long_string], "dict": {"value": long_string}},
|
||||
}
|
||||
sanitized = _sanitize_request_body_for_spend_logs_payload(request_body)
|
||||
|
||||
|
|
@ -631,7 +631,7 @@ def test_sanitize_request_body_for_spend_logs_payload_mixed_types():
|
|||
assert sanitized["number"] == 42
|
||||
assert sanitized["nested"]["list"][0] == "short"
|
||||
assert len(sanitized["nested"]["list"][1]) == expected_length
|
||||
assert len(sanitized["nested"]["dict"]["key"]) == expected_length
|
||||
assert len(sanitized["nested"]["dict"]["value"]) == expected_length
|
||||
|
||||
|
||||
def test_sanitize_request_body_for_spend_logs_payload_uses_runtime_env_override(
|
||||
|
|
@ -2781,10 +2781,12 @@ def test_proxy_server_request_payload_redacts_provider_credentials(mock_should_s
|
|||
assert parsed["messages"] == [{"role": "user", "content": "hello"}]
|
||||
|
||||
|
||||
def test_sanitize_request_body_keeps_credential_named_fields_by_default() -> None:
|
||||
response: Final = {"system_fingerprint": "fp_123", "usage": {"prompt_tokens": 1}}
|
||||
def test_sanitize_response_redacts_credential_named_fields() -> None:
|
||||
response: Final = {"access_token": "canary-oauth-token", "usage": {"prompt_tokens": 1}}
|
||||
|
||||
assert _sanitize_request_body_for_spend_logs_payload({"response": response}) == {"response": response}
|
||||
assert _sanitize_request_body_for_spend_logs_payload({"response": response}) == {
|
||||
"response": {"access_token": REDACTED_BY_LITELM_STRING, "usage": {"prompt_tokens": 1}}
|
||||
}
|
||||
|
||||
|
||||
@patch("litellm.proxy.spend_tracking.spend_tracking_utils.should_store_prompts_and_responses_in_spend_logs")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue