Merge pull request #22188 from BerriAI/litellm_langfuse_key_leakage

fix: langfuse trace leak key on model params
This commit is contained in:
yuneng-jiang
2026-03-16 23:46:06 -07:00
committed by GitHub
2 changed files with 37 additions and 18 deletions
+21 -4
View File
@@ -25,6 +25,7 @@ from litellm.litellm_core_utils.core_helpers import (
reconstruct_model_name,
filter_exceptions_from_params,
)
from litellm.litellm_core_utils.model_param_helper import ModelParamHelper
from litellm.litellm_core_utils.redact_messages import redact_user_api_key_info
from litellm.integrations.langfuse.langfuse_mock_client import (
create_mock_langfuse_client,
@@ -291,8 +292,6 @@ class LangFuseLogger:
functions = optional_params.pop("functions", None)
tools = optional_params.pop("tools", None)
# Remove secret_fields to prevent leaking sensitive data (e.g., authorization headers)
optional_params.pop("secret_fields", None)
if functions is not None:
prompt["functions"] = functions
if tools is not None:
@@ -505,13 +504,18 @@ class LangFuseLogger:
kwargs.get("model", ""), custom_llm_provider, metadata
)
# Use whitelisted model parameters to prevent leaking secrets
sanitized_model_params = ModelParamHelper.get_standard_logging_model_parameters(
optional_params
)
trace.generation(
CreateGeneration(
name=metadata.get("generation_name", "litellm-completion"),
startTime=start_time,
endTime=end_time,
model=model_name,
modelParameters=optional_params,
modelParameters=sanitized_model_params,
prompt=input,
completion=output,
usage={
@@ -831,13 +835,26 @@ class LangFuseLogger:
kwargs.get("model", ""), custom_llm_provider, metadata
)
# Use whitelisted model_parameters from StandardLoggingPayload
# to prevent leaking secrets (api_key, auth headers, etc.)
if standard_logging_object is not None:
sanitized_model_params = standard_logging_object.get(
"model_parameters", optional_params
)
else:
sanitized_model_params = (
ModelParamHelper.get_standard_logging_model_parameters(
optional_params
)
)
generation_params = {
"name": generation_name,
"id": clean_metadata.pop("generation_id", generation_id),
"start_time": start_time,
"end_time": end_time,
"model": model_name,
"model_parameters": optional_params,
"model_parameters": sanitized_model_params,
"input": input if not mask_input else "redacted-by-litellm",
"output": output if not mask_output else "redacted-by-litellm",
"usage": usage,
+16 -14
View File
@@ -5569,21 +5569,23 @@ def scrub_sensitive_keys_in_metadata(litellm_params: Optional[dict]):
litellm_params["_langfuse_masking_function"] = masking_fn
litellm_params["metadata"] = metadata
## check user_api_key_metadata for sensitive logging keys
cleaned_user_api_key_metadata = {}
if "user_api_key_metadata" in metadata and isinstance(
metadata["user_api_key_metadata"], dict
):
for k, v in metadata["user_api_key_metadata"].items():
if k == "logging": # prevent logging user logging keys
cleaned_user_api_key_metadata[k] = (
"scrubbed_by_litellm_for_sensitive_keys"
)
else:
cleaned_user_api_key_metadata[k] = v
## remove sensitive logging/callback keys from metadata dicts
## these contain credentials (langfuse_secret_key, langfuse_public_key, etc.)
_sensitive_keys = {"logging", "callback_settings"}
metadata["user_api_key_metadata"] = cleaned_user_api_key_metadata
litellm_params["metadata"] = metadata
for metadata_field in (
"user_api_key_metadata",
"user_api_key_auth_metadata",
"user_api_key_team_metadata",
):
if metadata_field in metadata and isinstance(metadata[metadata_field], dict):
for sensitive_key in _sensitive_keys:
metadata[metadata_field].pop(sensitive_key, None)
## remove user_api_key_auth entirely - contains full auth object with nested credentials
metadata.pop("user_api_key_auth", None)
litellm_params["metadata"] = metadata
return litellm_params