fix(proxy): guard extract_key_hash/extract_key_alias against a non-Mapping metadata field

Both called active.get(...) after an `or EMPTY_MAPPING` fallback that only
triggers on a falsy value, so a truthy non-Mapping (metadata can arrive as
an unparsed JSON string on multipart/extra_body routes) raised
AttributeError instead of falling through. order_tags_for_identity_resolution
already guarded the same pattern; applied the same isinstance check here.

Bugbot finding on commit 41be4a8782.
This commit is contained in:
Deepanshu 2026-09-01 10:40:57 -04:00
parent 41be4a8782
commit 3d4ba87e8c
2 changed files with 16 additions and 2 deletions

View file

@ -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

View file

@ -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