diff --git a/litellm/litellm_core_utils/sensitive_data_masker.py b/litellm/litellm_core_utils/sensitive_data_masker.py index 663c3fac80..8b88ef9482 100644 --- a/litellm/litellm_core_utils/sensitive_data_masker.py +++ b/litellm/litellm_core_utils/sensitive_data_masker.py @@ -21,6 +21,7 @@ class SensitiveDataMasker: "auth", "authorization", "credential", + "credentials", "access", "private", "certificate", diff --git a/litellm/proxy/common_utils/openai_endpoint_utils.py b/litellm/proxy/common_utils/openai_endpoint_utils.py index 7e5c83500a..c4bfe11aec 100644 --- a/litellm/proxy/common_utils/openai_endpoint_utils.py +++ b/litellm/proxy/common_utils/openai_endpoint_utils.py @@ -29,6 +29,7 @@ def remove_sensitive_info_from_deployment( deployment_dict["litellm_params"].pop("api_key", None) deployment_dict["litellm_params"].pop("client_secret", None) deployment_dict["litellm_params"].pop("vertex_credentials", None) + deployment_dict["litellm_params"].pop("vertex_ai_credentials", None) deployment_dict["litellm_params"].pop("aws_access_key_id", None) deployment_dict["litellm_params"].pop("aws_secret_access_key", None) diff --git a/tests/test_litellm/litellm_core_utils/test_sensitive_data_masker.py b/tests/test_litellm/litellm_core_utils/test_sensitive_data_masker.py index bb5c71ceb6..6808c4821c 100644 --- a/tests/test_litellm/litellm_core_utils/test_sensitive_data_masker.py +++ b/tests/test_litellm/litellm_core_utils/test_sensitive_data_masker.py @@ -65,12 +65,13 @@ def test_excluded_keys_exact_match(): # Non-sensitive keys should remain unchanged assert masked["port"] == 6379 - # Test case sensitivity - excluded_keys should be exact match + # Test case sensitivity - excluded_keys should be exact match. Supplying an + # uppercase variant must NOT exclude the lowercase key, so the field falls + # back to pattern matching ("credentials" is in the sensitive pattern set) + # and is masked. masked = masker.mask_dict(data, excluded_keys={"LITELLM_CREDENTIALS_NAME"}) - # Should still be masked because case doesn't match (exact match required) - assert ( - masked["litellm_credentials_name"] == "my-credential-name" - ) # Not masked because it doesn't match patterns anyway + assert masked["litellm_credentials_name"] != "my-credential-name" + assert "*" in masked["litellm_credentials_name"] # Test with api_key in excluded_keys to verify it works for keys that would be masked masked = masker.mask_dict(data, excluded_keys={"api_key"}) diff --git a/tests/test_litellm/proxy/common_utils/test_openai_endpoint_utils.py b/tests/test_litellm/proxy/common_utils/test_openai_endpoint_utils.py index f2ca41a2c9..44288b027a 100644 --- a/tests/test_litellm/proxy/common_utils/test_openai_endpoint_utils.py +++ b/tests/test_litellm/proxy/common_utils/test_openai_endpoint_utils.py @@ -1,3 +1,5 @@ +import copy + import pytest from litellm.proxy.common_utils.openai_endpoint_utils import ( @@ -86,7 +88,7 @@ def test_remove_sensitive_info_from_deployment_with_excluded_keys(): """ Test that excluded_keys prevents masking of specific keys (exact match). """ - model_config = { + base_config = { "model_name": "test-model", "litellm_params": { "model": "openai/gpt-4", @@ -98,13 +100,13 @@ def test_remove_sensitive_info_from_deployment_with_excluded_keys(): } # Without excluded_keys, access_token should be masked (contains "token") - sanitized_config = remove_sensitive_info_from_deployment(model_config) + sanitized_config = remove_sensitive_info_from_deployment(copy.deepcopy(base_config)) assert sanitized_config["litellm_params"]["access_token"] != "token-12345" assert "*" in sanitized_config["litellm_params"]["access_token"] # With excluded_keys, litellm_credentials_name should NOT be masked (even if it would match patterns) sanitized_config = remove_sensitive_info_from_deployment( - model_config, excluded_keys={"litellm_credentials_name"} + copy.deepcopy(base_config), excluded_keys={"litellm_credentials_name"} ) assert ( sanitized_config["litellm_params"]["litellm_credentials_name"]