diff --git a/litellm/proxy/hooks/tag_rate_limits_shared.py b/litellm/proxy/hooks/tag_rate_limits_shared.py index c16003cd3bf..6fa1cadac49 100644 --- a/litellm/proxy/hooks/tag_rate_limits_shared.py +++ b/litellm/proxy/hooks/tag_rate_limits_shared.py @@ -238,7 +238,7 @@ def extract_key_hash(request_kwargs: Mapping[str, object], metadata_variable_nam the plain name is already the hashed token (see `litellm_pre_call_utils.py`). """ active: Final = request_kwargs.get(metadata_variable_name) or EMPTY_MAPPING - key_hash: Final = active.get("user_api_key") + key_hash: Final = active.get("user_api_key") if isinstance(active, Mapping) else None return key_hash if isinstance(key_hash, str) else None @@ -249,7 +249,7 @@ def extract_key_alias(request_kwargs: Mapping[str, object], metadata_variable_na `metadata["user_api_key_alias"]` to `user_api_key_dict.key_alias` (see `litellm_pre_call_utils.py`).""" active: Final = request_kwargs.get(metadata_variable_name) or EMPTY_MAPPING - key_alias: Final = active.get("user_api_key_alias") + key_alias: Final = active.get("user_api_key_alias") if isinstance(active, Mapping) else None return key_alias if isinstance(key_alias, str) else None diff --git a/tests/test_litellm/proxy/hooks/test_tag_rate_limits_shared.py b/tests/test_litellm/proxy/hooks/test_tag_rate_limits_shared.py index 7bb9d04fef0..38747090c59 100644 --- a/tests/test_litellm/proxy/hooks/test_tag_rate_limits_shared.py +++ b/tests/test_litellm/proxy/hooks/test_tag_rate_limits_shared.py @@ -12,6 +12,7 @@ from litellm.proxy.hooks.tag_rate_limits_shared import ( bucket_ttl_seconds, entry_applies, extract_identity, + extract_key_alias, extract_key_hash, fixed_length_identity, order_tags_for_identity_resolution, @@ -125,6 +126,19 @@ def test_extract_key_hash_reads_metadata_when_it_is_the_authoritative_field(): assert extract_key_hash(request_kwargs, "metadata") == "real-hash" +def test_extract_key_hash_ignores_a_non_mapping_authoritative_field(): + """Bugbot finding: metadata can arrive as an unparsed JSON string (see + apply_client_tag_policy_pre_auth's own docstring on multipart/extra_body + routes); a truthy non-Mapping must not reach .get() and crash.""" + request_kwargs = {"metadata": '{"user_api_key": "forged"}'} + assert extract_key_hash(request_kwargs, "metadata") is None + + +def test_extract_key_alias_ignores_a_non_mapping_authoritative_field(): + request_kwargs = {"metadata": '{"user_api_key_alias": "forged"}'} + assert extract_key_alias(request_kwargs, "metadata") is None + + # --------------------------------------------------------------------------- # resolve_success_event_metadata_variable_name -- veria-ai finding surfaced on # PR #38347: a caller-supplied, non-empty litellm_metadata must not be