mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-03 02:22:24 +00:00
fix(batch_rate_limiter): enforce model access check before honoring skip paths
Admin-configured skips (disable_batch_input_file_rate_limiting, skip_batch_input_file_rate_limiting_for_models/_for_providers) and the no-applicable-rate-limits short-circuit previously bypassed _enforce_batch_file_model_access. A key with a restricted model allowlist could therefore submit a batch JSONL referencing models outside its allowlist whenever any of these skip paths fired, and the provider-skip path was attacker-controllable via the request body's custom_llm_provider field. Hoist the model-access guard to the top so restricted keys always have their JSONL validated regardless of which skip would otherwise apply. Co-authored-by: Yassin Kortam <yassin@berri.ai>
This commit is contained in:
parent
b391f772ad
commit
4f9ceddd52
2 changed files with 25 additions and 25 deletions
|
|
@ -145,23 +145,25 @@ class _PROXY_BatchRateLimiter(CustomLogger):
|
|||
"""
|
||||
Skip downloading batch input files when configured or when there is
|
||||
nothing to enforce (no applicable rate limits and no model allowlist).
|
||||
|
||||
When the caller's key has a model allowlist to enforce, no skip path
|
||||
is honored: the JSONL must still be downloaded so
|
||||
``_enforce_batch_file_model_access`` can validate every ``body.model``
|
||||
entry. Otherwise a restricted key could smuggle unauthorized models
|
||||
into the file via an admin-configured skip (global disable,
|
||||
per-model, per-provider) or via the user-controlled
|
||||
``custom_llm_provider`` field.
|
||||
"""
|
||||
if self._key_requires_batch_model_access_check(user_api_key_dict):
|
||||
return False
|
||||
|
||||
from litellm.proxy.proxy_server import general_settings
|
||||
|
||||
if general_settings.get("disable_batch_input_file_rate_limiting") is True:
|
||||
return True
|
||||
|
||||
# Only honor the metadata-based skip when the key has no model
|
||||
# allowlist to enforce. Otherwise a caller could set this flag in
|
||||
# the request body (it lands in ``litellm_metadata`` for batch
|
||||
# routes) and skip ``_enforce_batch_file_model_access``, smuggling
|
||||
# restricted models into the JSONL.
|
||||
litellm_metadata = data.get("litellm_metadata") or {}
|
||||
if litellm_metadata.get(
|
||||
"skip_batch_input_file_rate_limiting"
|
||||
) is True and not self._key_requires_batch_model_access_check(
|
||||
user_api_key_dict
|
||||
):
|
||||
if litellm_metadata.get("skip_batch_input_file_rate_limiting") is True:
|
||||
return True
|
||||
|
||||
batch_model = self._get_batch_routing_model(data)
|
||||
|
|
@ -189,19 +191,18 @@ class _PROXY_BatchRateLimiter(CustomLogger):
|
|||
)
|
||||
return True
|
||||
|
||||
if not self._key_requires_batch_model_access_check(user_api_key_dict):
|
||||
descriptors = self.parallel_request_limiter._create_rate_limit_descriptors(
|
||||
user_api_key_dict=user_api_key_dict,
|
||||
data=data,
|
||||
rpm_limit_type=None,
|
||||
tpm_limit_type=None,
|
||||
model_has_failures=False,
|
||||
descriptors = self.parallel_request_limiter._create_rate_limit_descriptors(
|
||||
user_api_key_dict=user_api_key_dict,
|
||||
data=data,
|
||||
rpm_limit_type=None,
|
||||
tpm_limit_type=None,
|
||||
model_has_failures=False,
|
||||
)
|
||||
if not self._has_applicable_batch_rate_limits(descriptors):
|
||||
verbose_proxy_logger.debug(
|
||||
"Skipping batch input file processing: no rate limits configured"
|
||||
)
|
||||
if not self._has_applicable_batch_rate_limits(descriptors):
|
||||
verbose_proxy_logger.debug(
|
||||
"Skipping batch input file processing: no rate limits configured"
|
||||
)
|
||||
return True
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ from fastapi import HTTPException
|
|||
|
||||
from litellm.proxy._types import LitellmUserRoles, UserAPIKeyAuth
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Token counter — covers all three batch payload shapes
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -268,7 +267,7 @@ async def test_pre_call_skips_file_fetch_when_disabled_in_general_settings():
|
|||
internal_usage_cache=MagicMock(),
|
||||
parallel_request_limiter=MagicMock(),
|
||||
)
|
||||
user = UserAPIKeyAuth(api_key="sk-ok", user_id="alice", models=["gpt-4o"])
|
||||
user = UserAPIKeyAuth(api_key="sk-ok", user_id="alice", models=["*"])
|
||||
|
||||
with patch(
|
||||
"litellm.proxy.proxy_server.general_settings",
|
||||
|
|
@ -293,7 +292,7 @@ async def test_pre_call_skips_file_fetch_for_configured_provider():
|
|||
internal_usage_cache=MagicMock(),
|
||||
parallel_request_limiter=MagicMock(),
|
||||
)
|
||||
user = UserAPIKeyAuth(api_key="sk-ok", user_id="alice", models=["gpt-4o"])
|
||||
user = UserAPIKeyAuth(api_key="sk-ok", user_id="alice", models=["*"])
|
||||
|
||||
with patch(
|
||||
"litellm.proxy.proxy_server.general_settings",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue