chore(proxy): redact query-string secrets in URL-valued callback vars

A URL-valued callback var (e.g. GENERIC_LOGGER_ENDPOINT) can carry a token as
a query param, which userinfo-only redaction missed. Apply mask_url_query_values
alongside mask_url_credentials on the masked /get/config/callbacks path.
This commit is contained in:
user 2026-05-31 00:42:18 +00:00
parent 3b1b13fc94
commit c18ad848ff
No known key found for this signature in database
2 changed files with 25 additions and 1 deletions

View file

@ -9,6 +9,7 @@ from litellm.litellm_core_utils.sensitive_data_masker import (
SensitiveDataMasker,
mask_sensitive_keys,
mask_url_credentials,
mask_url_query_values,
)
from litellm.proxy._types import CommonProxyErrors, LiteLLMPromptInjectionParams
from litellm.proxy.common_utils.encrypt_decrypt_utils import (
@ -652,7 +653,12 @@ def process_callback(
if _is_sensitive_callback_var(k) or k.upper().endswith("_HEADERS")
}
env_vars_dict = mask_sensitive_keys(env_vars_dict, sensitive_keys)
env_vars_dict = {k: mask_url_credentials(v) for k, v in env_vars_dict.items()}
# URL-valued callback vars (e.g. GENERIC_LOGGER_ENDPOINT) can embed a
# token in userinfo or as a query param, so redact both.
env_vars_dict = {
k: mask_url_query_values(mask_url_credentials(v))
for k, v in env_vars_dict.items()
}
return {"name": _callback, "variables": env_vars_dict, "type": callback_type}

View file

@ -163,6 +163,24 @@ def test_process_callback_masks_headers_vars(mock_get_env_vars):
assert result["variables"]["OTEL_ENDPOINT"] == "http://collector.internal:4317"
@patch(
"litellm.proxy.common_utils.callback_utils.CustomLogger.get_callback_env_vars",
return_value=["GENERIC_LOGGER_ENDPOINT"],
)
def test_process_callback_masks_url_query_secrets(mock_get_env_vars):
"""A URL-valued callback var can carry a token as a query param; it is
redacted even though the var name is not credential-like."""
result = process_callback(
_callback="generic",
callback_type="success",
environment_variables={
"GENERIC_LOGGER_ENDPOINT": "https://logs.example.com/ingest?token=qp-secret-token"
},
mask_sensitive=True,
)
assert "qp-secret-token" not in result["variables"]["GENERIC_LOGGER_ENDPOINT"]
def test_normalize_callback_names_none_returns_empty_list():
assert normalize_callback_names(None) == []
assert normalize_callback_names([]) == []