mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-08 22:21:35 +00:00
fix(logging): scrub callback config params to prevent credential leak in Langfuse and other loggers
- Add scrub_callback_config_params_from_dict using _supported_callback_params - Apply at litellm_logging layer so all callbacks (Langfuse, Langsmith, etc.) are protected - Remove Langfuse-specific filter; fix is now centralized - Add test_scrub_callback_config_params_removes_credentials - Add before/after screenshots showing secret leak fixed Made-with: Cursor
This commit is contained in:
parent
628510d1b5
commit
eacdbd19cf
6 changed files with 85 additions and 34 deletions
|
|
@ -20,16 +20,16 @@ from packaging.version import Version
|
|||
import litellm
|
||||
from litellm._logging import verbose_logger
|
||||
from litellm.constants import MAX_LANGFUSE_INITIALIZED_CLIENTS
|
||||
from litellm.litellm_core_utils.core_helpers import (
|
||||
safe_deep_copy,
|
||||
reconstruct_model_name,
|
||||
filter_exceptions_from_params,
|
||||
)
|
||||
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,
|
||||
should_use_langfuse_mock,
|
||||
)
|
||||
from litellm.litellm_core_utils.core_helpers import (
|
||||
filter_exceptions_from_params,
|
||||
reconstruct_model_name,
|
||||
safe_deep_copy,
|
||||
)
|
||||
from litellm.litellm_core_utils.redact_messages import redact_user_api_key_info
|
||||
from litellm.llms.custom_httpx.http_handler import _get_httpx_client
|
||||
from litellm.secret_managers.main import str_to_bool
|
||||
from litellm.types.integrations.langfuse import *
|
||||
|
|
@ -272,7 +272,9 @@ class LangFuseLogger:
|
|||
"""
|
||||
try:
|
||||
verbose_logger.debug(
|
||||
f"Langfuse Logging - Enters logging function for model {kwargs}"
|
||||
"Langfuse Logging - Enters logging function for model call_type=%s litellm_call_id=%s",
|
||||
kwargs.get("call_type"),
|
||||
kwargs.get("litellm_call_id"),
|
||||
)
|
||||
|
||||
# set default values for input/output for langfuse logging
|
||||
|
|
|
|||
|
|
@ -1,36 +1,60 @@
|
|||
from typing import Dict, Optional
|
||||
|
||||
from litellm.secret_managers.main import get_secret_str
|
||||
from litellm.types.utils import StandardCallbackDynamicParams
|
||||
|
||||
# Hardcoded list of supported callback params to avoid runtime inspection issues with TypedDict
|
||||
# Callback config params - never send to external loggers (credential leak)
|
||||
_SUPPORTED_CALLBACK_PARAMS_FROZEN = frozenset(
|
||||
[
|
||||
"langfuse_public_key",
|
||||
"langfuse_secret",
|
||||
"langfuse_secret_key",
|
||||
"langfuse_host",
|
||||
"langfuse_prompt_version",
|
||||
"gcs_bucket_name",
|
||||
"gcs_path_service_account",
|
||||
"langsmith_api_key",
|
||||
"langsmith_project",
|
||||
"langsmith_base_url",
|
||||
"langsmith_sampling_rate",
|
||||
"langsmith_tenant_id",
|
||||
"humanloop_api_key",
|
||||
"arize_api_key",
|
||||
"arize_space_key",
|
||||
"arize_space_id",
|
||||
"posthog_api_key",
|
||||
"posthog_host",
|
||||
"braintrust_api_key",
|
||||
"braintrust_project",
|
||||
"braintrust_host",
|
||||
"slack_webhook_url",
|
||||
"lunary_public_key",
|
||||
"turn_off_message_logging",
|
||||
"litellm_logging_obj",
|
||||
"environment_variables",
|
||||
]
|
||||
)
|
||||
|
||||
# List form for iteration (excludes litellm_logging_obj, environment_variables - config only)
|
||||
_supported_callback_params = [
|
||||
"langfuse_public_key",
|
||||
"langfuse_secret",
|
||||
"langfuse_secret_key",
|
||||
"langfuse_host",
|
||||
"langfuse_prompt_version",
|
||||
"gcs_bucket_name",
|
||||
"gcs_path_service_account",
|
||||
"langsmith_api_key",
|
||||
"langsmith_project",
|
||||
"langsmith_base_url",
|
||||
"langsmith_sampling_rate",
|
||||
"langsmith_tenant_id",
|
||||
"humanloop_api_key",
|
||||
"arize_api_key",
|
||||
"arize_space_key",
|
||||
"arize_space_id",
|
||||
"posthog_api_key",
|
||||
"posthog_host",
|
||||
"braintrust_api_key",
|
||||
"braintrust_project",
|
||||
"braintrust_host",
|
||||
"slack_webhook_url",
|
||||
"lunary_public_key",
|
||||
"turn_off_message_logging",
|
||||
p for p in _SUPPORTED_CALLBACK_PARAMS_FROZEN if p not in ("litellm_logging_obj", "environment_variables")
|
||||
]
|
||||
|
||||
|
||||
def scrub_callback_config_params_from_dict(data: Dict) -> Dict:
|
||||
if not data:
|
||||
return data
|
||||
keys_to_remove = [
|
||||
k for k in data
|
||||
if k in _SUPPORTED_CALLBACK_PARAMS_FROZEN
|
||||
or k.endswith("_secret_key")
|
||||
or k.endswith("_secret")
|
||||
or k.endswith("_api_key")
|
||||
]
|
||||
result = {k: v for k, v in data.items() if k not in keys_to_remove}
|
||||
return result
|
||||
|
||||
|
||||
def initialize_standard_callback_dynamic_params(
|
||||
kwargs: Optional[Dict] = None,
|
||||
) -> StandardCallbackDynamicParams:
|
||||
|
|
|
|||
|
|
@ -61,6 +61,9 @@ from litellm.integrations.mlflow import MlflowLogger
|
|||
from litellm.integrations.sqs import SQSLogger
|
||||
from litellm.litellm_core_utils.core_helpers import reconstruct_model_name
|
||||
from litellm.litellm_core_utils.get_litellm_params import get_litellm_params
|
||||
from litellm.litellm_core_utils.initialize_dynamic_callback_params import (
|
||||
scrub_callback_config_params_from_dict,
|
||||
)
|
||||
from litellm.litellm_core_utils.llm_cost_calc.tool_call_cost_tracking import (
|
||||
StandardBuiltInToolCostTracking,
|
||||
)
|
||||
|
|
@ -537,11 +540,14 @@ class Logging(LiteLLMLoggingBaseClass):
|
|||
if _is_debugging_on() or self.litellm_request_debug:
|
||||
verbose_logger.debug(f"self.optional_params: {self.optional_params}")
|
||||
|
||||
sanitized_optional_params = scrub_callback_config_params_from_dict(
|
||||
dict(optional_params)
|
||||
)
|
||||
self.model_call_details.update(
|
||||
{
|
||||
"model": self.model,
|
||||
"messages": self.messages,
|
||||
"optional_params": self.optional_params,
|
||||
"optional_params": sanitized_optional_params,
|
||||
"litellm_params": self.litellm_params,
|
||||
"start_time": self.start_time,
|
||||
"stream": self.stream,
|
||||
|
|
@ -550,7 +556,7 @@ class Logging(LiteLLMLoggingBaseClass):
|
|||
"litellm_call_id": self.litellm_call_id,
|
||||
"completion_start_time": self.completion_start_time,
|
||||
"standard_callback_dynamic_params": self.standard_callback_dynamic_params,
|
||||
**self.optional_params,
|
||||
**sanitized_optional_params,
|
||||
**additional_params,
|
||||
}
|
||||
)
|
||||
|
|
|
|||
BIN
repro_secret_leak/before_after/after_secret_fixed.png
Normal file
BIN
repro_secret_leak/before_after/after_secret_fixed.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 925 KiB |
BIN
repro_secret_leak/before_after/before_secret_leak.png
Normal file
BIN
repro_secret_leak/before_after/before_secret_leak.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 956 KiB |
|
|
@ -5,6 +5,7 @@ sys.path.insert(0, os.path.abspath("../.."))
|
|||
|
||||
from litellm.litellm_core_utils.initialize_dynamic_callback_params import (
|
||||
initialize_standard_callback_dynamic_params,
|
||||
scrub_callback_config_params_from_dict,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -47,6 +48,24 @@ def test_dynamic_key_extraction_from_litellm_params_metadata():
|
|||
assert params.get("langfuse_secret_key") == "sk-litellm"
|
||||
|
||||
|
||||
def test_scrub_callback_config_params_removes_credentials():
|
||||
"""Scrub removes callback config/credentials before passing to loggers."""
|
||||
data = {
|
||||
"messages": "[{'role': 'user', 'content': 'Hi'}]",
|
||||
"langfuse_public_key": "pk-lf-xxx",
|
||||
"langfuse_secret": "sk-lf-4be1b432-61f4-4771-82a2-a33d3822ad65",
|
||||
"langfuse_host": "http://localhost:9999",
|
||||
"litellm_logging_obj": "<Logging object>",
|
||||
}
|
||||
result = scrub_callback_config_params_from_dict(data)
|
||||
assert "messages" in result
|
||||
assert "langfuse_secret" not in result
|
||||
assert "langfuse_public_key" not in result
|
||||
assert "langfuse_host" not in result
|
||||
assert "litellm_logging_obj" not in result
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_dynamic_key_extraction_from_metadata()
|
||||
test_dynamic_key_extraction_from_litellm_params_metadata()
|
||||
test_scrub_callback_config_params_removes_credentials()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue