extend reformatting to bracket-notation form metadata
Some checks failed
Unit Tests: Caching (Redis) / caching-redis (push) Has been cancelled
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Has been cancelled
Unit Tests: Security / security (push) Has been cancelled
Unit Tests: Proxy DB Operations / auth-checks (push) Has been cancelled
Unit Tests: Proxy DB Operations / budgets (push) Has been cancelled
Unit Tests: Proxy DB Operations / custom-logging (push) Has been cancelled
Unit Tests: Proxy DB Operations / db-and-spend (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-runtime (push) Has been cancelled
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Has been cancelled
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Has been cancelled
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Has been cancelled
Unit Tests: Proxy DB Operations / key-generation (push) Has been cancelled
Unit Tests: Proxy DB Operations / logging-misc (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-server-core (push) Has been cancelled
Unit Tests: Proxy DB Operations / schema-migration (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-utils (push) Has been cancelled

This commit is contained in:
Michael Riad Zaky 2026-04-25 11:41:57 -07:00
parent fa22f05daf
commit 737b0c0460
2 changed files with 37 additions and 0 deletions

View file

@ -539,6 +539,11 @@ def extract_nested_form_metadata(
verbose_proxy_logger.error(f"Error parsing metadata key '{key}': {str(e)}")
continue
# Same ingress sanitization as _read_request_body / get_form_data —
# this function is reached from endpoints that call request.form()
# directly (file uploads via files_endpoints.py), so without this the
# bracket-notation form path bypasses the strip applied elsewhere.
_strip_internal_metadata_keys(metadata)
return metadata

View file

@ -1165,6 +1165,38 @@ class TestStripInternalControlFields:
assert result["model"] == "whisper-1"
assert result["file"] == "<binary>"
def test_extract_nested_form_metadata_strips_restricted_fields(self):
"""File-upload endpoints reach extract_nested_form_metadata via
request.form() directly, bypassing _read_request_body /
get_form_data. Bracket-notation keys like
``litellm_metadata[applied_guardrails]`` and
``litellm_metadata[user_api_key_user_id]`` would otherwise survive
the assembly step and land in the request data unsanitized."""
from litellm.proxy.common_utils.http_parsing_utils import (
extract_nested_form_metadata,
)
form_data = {
"litellm_metadata[applied_guardrails]": "presidio-pii",
"litellm_metadata[user_api_key_user_id]": "caller-supplied",
"litellm_metadata[user_api_key_team_id]": "caller-supplied",
"litellm_metadata[pillar_response_headers]": "caller",
"litellm_metadata[spend_logs_metadata][owner]": "alice",
"litellm_metadata[tags]": "production",
"purpose": "fine-tune", # outside the prefix, ignored
}
result = extract_nested_form_metadata(
form_data=form_data, prefix="litellm_metadata["
)
# Restricted keys (exact match and prefix) are removed.
assert "applied_guardrails" not in result
assert "user_api_key_user_id" not in result
assert "user_api_key_team_id" not in result
assert "pillar_response_headers" not in result
# Non-restricted keys (including nested ones) survive.
assert result["spend_logs_metadata"] == {"owner": "alice"}
assert result["tags"] == "production"
@pytest.mark.asyncio
async def test_get_request_body_dispatcher_strips_multipart(
self, monkeypatch