mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-08 03:08:45 +00:00
removed jwt tokens from detailed_debug logging
This commit is contained in:
parent
af3acdda18
commit
82204d3e97
3 changed files with 85 additions and 7 deletions
|
|
@ -252,6 +252,34 @@ def clean_headers(
|
||||||
return clean_headers
|
return clean_headers
|
||||||
|
|
||||||
|
|
||||||
|
def _mask_secret_fields_for_logging(secret_fields: dict) -> dict:
|
||||||
|
"""
|
||||||
|
Masks sensitive values (like JWT tokens) in secret_fields before logging.
|
||||||
|
Keeps the field structure intact but redacts authorization header values.
|
||||||
|
"""
|
||||||
|
_sensitive_header_keys = frozenset(
|
||||||
|
{"authorization", "x-api-key", "api-key", "x-litellm-api-key"}
|
||||||
|
)
|
||||||
|
if not isinstance(secret_fields, dict):
|
||||||
|
return secret_fields
|
||||||
|
masked = {}
|
||||||
|
for field_key, field_value in secret_fields.items():
|
||||||
|
if isinstance(field_value, dict):
|
||||||
|
masked_inner = {}
|
||||||
|
for k, v in field_value.items():
|
||||||
|
if k.lower() in _sensitive_header_keys and isinstance(v, str):
|
||||||
|
if len(v) > 20:
|
||||||
|
masked_inner[k] = v[:10] + "****" + v[-4:]
|
||||||
|
else:
|
||||||
|
masked_inner[k] = "****"
|
||||||
|
else:
|
||||||
|
masked_inner[k] = v
|
||||||
|
masked[field_key] = masked_inner
|
||||||
|
else:
|
||||||
|
masked[field_key] = field_value
|
||||||
|
return masked
|
||||||
|
|
||||||
|
|
||||||
class LiteLLMProxyRequestSetup:
|
class LiteLLMProxyRequestSetup:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_timeout_from_request(headers: dict) -> Optional[float]:
|
def _get_timeout_from_request(headers: dict) -> Optional[float]:
|
||||||
|
|
@ -899,13 +927,19 @@ async def add_litellm_data_to_request( # noqa: PLR0915
|
||||||
|
|
||||||
## Cache Controls
|
## Cache Controls
|
||||||
headers = request.headers
|
headers = request.headers
|
||||||
verbose_proxy_logger.debug("Request Headers: %s", headers)
|
verbose_proxy_logger.debug("Request Headers: %s", clean_headers(headers))
|
||||||
cache_control_header = headers.get("Cache-Control", None)
|
cache_control_header = headers.get("Cache-Control", None)
|
||||||
if cache_control_header:
|
if cache_control_header:
|
||||||
cache_dict = parse_cache_control(cache_control_header)
|
cache_dict = parse_cache_control(cache_control_header)
|
||||||
data["ttl"] = cache_dict.get("s-maxage")
|
data["ttl"] = cache_dict.get("s-maxage")
|
||||||
|
|
||||||
verbose_proxy_logger.debug("receiving data: %s", data)
|
verbose_proxy_logger.debug(
|
||||||
|
"receiving data: %s",
|
||||||
|
{
|
||||||
|
k: (_mask_secret_fields_for_logging(v) if k == "secret_fields" else v)
|
||||||
|
for k, v in data.items()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
# Parse metadata if it's a string (e.g., from multipart/form-data)
|
# Parse metadata if it's a string (e.g., from multipart/form-data)
|
||||||
if "metadata" in data and data["metadata"] is not None:
|
if "metadata" in data and data["metadata"] is not None:
|
||||||
|
|
@ -1133,7 +1167,11 @@ async def add_litellm_data_to_request( # noqa: PLR0915
|
||||||
)
|
)
|
||||||
|
|
||||||
verbose_proxy_logger.debug(
|
verbose_proxy_logger.debug(
|
||||||
"[PROXY] returned data from litellm_pre_call_utils: %s", data
|
"[PROXY] returned data from litellm_pre_call_utils: %s",
|
||||||
|
{
|
||||||
|
k: (_mask_secret_fields_for_logging(v) if k == "secret_fields" else v)
|
||||||
|
for k, v in data.items()
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
## ENFORCED PARAMS CHECK
|
## ENFORCED PARAMS CHECK
|
||||||
|
|
|
||||||
|
|
@ -328,7 +328,11 @@ from litellm.proxy.hooks.prompt_injection_detection import (
|
||||||
)
|
)
|
||||||
from litellm.proxy.hooks.proxy_track_cost_callback import _ProxyDBLogger
|
from litellm.proxy.hooks.proxy_track_cost_callback import _ProxyDBLogger
|
||||||
from litellm.proxy.image_endpoints.endpoints import router as image_router
|
from litellm.proxy.image_endpoints.endpoints import router as image_router
|
||||||
from litellm.proxy.litellm_pre_call_utils import add_litellm_data_to_request
|
from litellm.proxy.litellm_pre_call_utils import (
|
||||||
|
_mask_secret_fields_for_logging,
|
||||||
|
add_litellm_data_to_request,
|
||||||
|
clean_headers,
|
||||||
|
)
|
||||||
from litellm.proxy.management_endpoints.budget_management_endpoints import (
|
from litellm.proxy.management_endpoints.budget_management_endpoints import (
|
||||||
router as budget_management_router,
|
router as budget_management_router,
|
||||||
)
|
)
|
||||||
|
|
@ -9838,11 +9842,17 @@ async def async_queue_request(
|
||||||
data["proxy_server_request"] = {
|
data["proxy_server_request"] = {
|
||||||
"url": str(request.url),
|
"url": str(request.url),
|
||||||
"method": request.method,
|
"method": request.method,
|
||||||
"headers": dict(request.headers),
|
"headers": clean_headers(request.headers),
|
||||||
"body": copy.copy(data), # use copy instead of deepcopy
|
"body": copy.copy(data), # use copy instead of deepcopy
|
||||||
}
|
}
|
||||||
|
|
||||||
verbose_proxy_logger.debug("receiving data: %s", data)
|
verbose_proxy_logger.debug(
|
||||||
|
"receiving data: %s",
|
||||||
|
{
|
||||||
|
k: (_mask_secret_fields_for_logging(v) if k == "secret_fields" else v)
|
||||||
|
for k, v in data.items()
|
||||||
|
},
|
||||||
|
)
|
||||||
data["model"] = (
|
data["model"] = (
|
||||||
general_settings.get("completion_model", None) # server default
|
general_settings.get("completion_model", None) # server default
|
||||||
or user_model # model name passed via cli args
|
or user_model # model name passed via cli args
|
||||||
|
|
|
||||||
|
|
@ -7267,6 +7267,32 @@ def get_valid_models(
|
||||||
return [] # NON-Blocking
|
return [] # NON-Blocking
|
||||||
|
|
||||||
|
|
||||||
|
def _mask_secret_fields_for_logging(secret_fields: dict) -> dict:
|
||||||
|
"""
|
||||||
|
Masks sensitive values (like JWT tokens) in secret_fields before logging.
|
||||||
|
Keeps the field structure intact but redacts authorization header values.
|
||||||
|
"""
|
||||||
|
if not isinstance(secret_fields, dict):
|
||||||
|
return secret_fields
|
||||||
|
masked = {}
|
||||||
|
for field_key, field_value in secret_fields.items():
|
||||||
|
if isinstance(field_value, dict):
|
||||||
|
masked_inner = {}
|
||||||
|
for k, v in field_value.items():
|
||||||
|
if k.lower() in ("authorization", "x-api-key", "api-key", "x-litellm-api-key") and isinstance(v, str):
|
||||||
|
# Show first 10 and last 4 chars, mask the rest
|
||||||
|
if len(v) > 20:
|
||||||
|
masked_inner[k] = v[:10] + "****" + v[-4:]
|
||||||
|
else:
|
||||||
|
masked_inner[k] = "****"
|
||||||
|
else:
|
||||||
|
masked_inner[k] = v
|
||||||
|
masked[field_key] = masked_inner
|
||||||
|
else:
|
||||||
|
masked[field_key] = field_value
|
||||||
|
return masked
|
||||||
|
|
||||||
|
|
||||||
def print_args_passed_to_litellm(original_function, args, kwargs):
|
def print_args_passed_to_litellm(original_function, args, kwargs):
|
||||||
if not _is_debugging_on():
|
if not _is_debugging_on():
|
||||||
return
|
return
|
||||||
|
|
@ -7292,7 +7318,11 @@ def print_args_passed_to_litellm(original_function, args, kwargs):
|
||||||
return
|
return
|
||||||
|
|
||||||
args_str = ", ".join(map(repr, args))
|
args_str = ", ".join(map(repr, args))
|
||||||
kwargs_str = ", ".join(f"{key}={repr(value)}" for key, value in kwargs.items())
|
# Mask JWT tokens / auth headers in secret_fields before logging
|
||||||
|
kwargs_str = ", ".join(
|
||||||
|
f"{key}={repr(_mask_secret_fields_for_logging(value)) if key == 'secret_fields' else repr(value)}"
|
||||||
|
for key, value in kwargs.items()
|
||||||
|
)
|
||||||
print_verbose(
|
print_verbose(
|
||||||
"\n",
|
"\n",
|
||||||
) # new line before
|
) # new line before
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue