fix(proxy): enforce fallback model access by default (#46127)

This commit is contained in:
moyai-devin-berriai[bot] 2026-10-13 07:58:53 -07:00 • committed by GitHub
parent 6b7d1928b8
commit 0976c0889a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 26 additions and 6 deletions

View file

@ -2796,7 +2796,7 @@ class ConfigGeneralSettings(LiteLLMPydanticObjectBase):
)
enforce_fallback_model_access: bool | None = Field(
None,
description="If True, router fallbacks configured in router_settings are only attempted when the calling key (and its team and project) is allowed to call the fallback model; unauthorized fallback targets are skipped and the primary model's error is returned. Default is False.",
description="If True, router fallbacks configured in router_settings are only attempted when the calling key (and its team and project) is allowed to call the fallback model; unauthorized fallback targets are skipped and the primary model's error is returned. Default is True. Set False to disable fallback model access enforcement.",
)
disable_fallbacks_on_per_model_rate_limits: bool | None = Field(
None,

View file

@ -4,8 +4,8 @@ Authorize router fallback targets against the caller's key, team and project mod
`_enforce_key_and_fallback_model_access` only sees fallbacks the client sends in the request body.
Fallbacks configured on the router (`router_settings.fallbacks` and friends) are chosen after auth,
inside the router, so this predicate is injected into the router to re-run the same model access
checks for each fallback target before it is attempted. Opt-in via
`general_settings.enforce_fallback_model_access: true`. Fallbacks of a search request always run the
checks for each fallback target before it is attempted. Enabled by default. Opt out via
`general_settings.enforce_fallback_model_access: false`. Fallbacks of a search request always run the
key, team and user search tool grants instead, the same check /search runs on the requested tool.
"""
@ -28,7 +28,7 @@ class _RequestMetadata(LiteLLMBaseModel):
class _FallbackAccessSettings(LiteLLMBaseModel):
enforce_fallback_model_access: bool = False
enforce_fallback_model_access: bool = True
async def is_model_authorized_for_token(*, model: str, valid_token: UserAPIKeyAuth, llm_router: Router) -> bool:

View file

@ -1,3 +1,5 @@
from typing import Final
import pytest
from litellm import Router
@ -89,8 +91,9 @@ async def test_check_allows_every_fallback_while_not_enforced():
@pytest.mark.parametrize(
("general_settings", "expected"),
[
({}, True),
({}, False),
({"enforce_fallback_model_access": False}, True),
({"enforce_fallback_model_access": "false"}, True),
({"enforce_fallback_model_access": True}, False),
({"enforce_fallback_model_access": "true"}, False),
],
@ -100,6 +103,9 @@ async def test_proxy_check_reads_enforce_fallback_model_access_from_general_sett
):
monkeypatch.setattr("litellm.proxy.proxy_server.general_settings", general_settings)
assert await router_fallback_access_check(
model="open-model", request_kwargs=_request_with_key(), llm_router=_router()
)
assert (
await router_fallback_access_check(
model="secret-model", request_kwargs=_request_with_key(), llm_router=_router()
@ -172,3 +178,17 @@ async def test_fallback_named_like_both_a_model_and_a_search_tool_follows_the_re
)
assert allowed is expected
@pytest.mark.asyncio
@pytest.mark.parametrize("metadata_field", ["metadata", "litellm_metadata"])
async def test_default_check_enforces_team_models_for_a_key_without_model_restrictions(
monkeypatch: pytest.MonkeyPatch, metadata_field: str
) -> None:
monkeypatch.setattr("litellm.proxy.proxy_server.general_settings", {})
router: Final = _router()
token: Final = UserAPIKeyAuth(api_key="hashed", models=[], team_id="qa-team", team_models=["open-model"])
request_kwargs: Final = {metadata_field: {"user_api_key_auth": token}}
assert await router_fallback_access_check(model="open-model", request_kwargs=request_kwargs, llm_router=router)
assert not await router_fallback_access_check(model="secret-model", request_kwargs=request_kwargs, llm_router=router)

View file

@ -29601,7 +29601,7 @@ export interface components {
enable_public_model_hub: boolean;
/**
* Enforce Fallback Model Access
* @description If True, router fallbacks configured in router_settings are only attempted when the calling key (and its team and project) is allowed to call the fallback model; unauthorized fallback targets are skipped and the primary model's error is returned. Default is False.
* @description If True, router fallbacks configured in router_settings are only attempted when the calling key (and its team and project) is allowed to call the fallback model; unauthorized fallback targets are skipped and the primary model's error is returned. Default is True. Set False to disable fallback model access enforcement.
*/
enforce_fallback_model_access?: boolean | null;
/**