fix(batch_rate_limiter): drop client-controlled skip flag to close quota bypass

The litellm_metadata.skip_batch_input_file_rate_limiting flag was read
straight from the request body, so any caller whose key had unrestricted
model access could send it and skip the input-file download, token count,
and RPM/TPM reservation, bypassing their batch rate limits. Skip decisions
now derive only from server-controlled general_settings.
This commit is contained in:
mateo-berri 2026-05-30 04:00:05 +00:00 • committed by Claude
parent 1e71bdd6e7
commit 9d5ea6f3fb
No known key found for this signature in database
2 changed files with 9 additions and 7 deletions

View file

@ -208,10 +208,6 @@ class _PROXY_BatchRateLimiter(CustomLogger):
if general_settings.get("disable_batch_input_file_rate_limiting") is True:
return True, None
litellm_metadata = data.get("litellm_metadata") or {}
if litellm_metadata.get("skip_batch_input_file_rate_limiting") is True:
return True, None
batch_model = self._get_batch_routing_model(data)
skip_models = (
general_settings.get("skip_batch_input_file_rate_limiting_for_models") or []

View file

@ -637,8 +637,15 @@ def test_should_skip_returns_false_when_key_needs_model_access_check():
assert descriptors is None
def test_should_skip_honors_litellm_metadata_flag():
def test_should_skip_ignores_client_supplied_metadata_flag():
"""A caller must not be able to bypass batch rate limits by setting
``litellm_metadata.skip_batch_input_file_rate_limiting`` in the request
body. The skip decision is server-controlled only, so with applicable rate
limits the JSONL is still processed despite the client flag."""
rate_limiter = _make_rate_limiter()
rate_limiter.parallel_request_limiter._create_rate_limit_descriptors.return_value = [
{"rate_limit": {"requests_per_unit": 5}}
]
user = UserAPIKeyAuth(api_key="sk", models=["*"])
with patch("litellm.proxy.proxy_server.general_settings", {}):
should_skip, descriptors = (
@ -650,8 +657,7 @@ def test_should_skip_honors_litellm_metadata_flag():
user_api_key_dict=user,
)
)
assert should_skip is True
assert descriptors is None
assert should_skip is False
def test_should_skip_honors_per_model_skip_list():