[Infra] Merge dev branch - #27032
Conversation
Two changes that together prevent a caller from smuggling unauthorized
models past the API key's allowlist via per-request router overrides.
1. ``_enforce_key_and_fallback_model_access``: also walk fallback models
nested inside ``router_settings_override.fallbacks`` /
``context_window_fallbacks`` / ``content_policy_fallbacks``.
``route_llm_request.py`` promotes those to per-request kwargs after
auth, so without this they bypassed the model allowlist entirely.
New ``iter_router_fallback_model_names`` helper extracts leaf names
from both the simple top-level shape (str | {"model": str}) and the
nested router-config shape ({primary: [fallbacks]}). The two fallback
validation loops are unified — every name (top-level + override) is
deduplicated and validated once via ``can_key_call_model`` +
``is_valid_fallback_model``.
2. ``route_request``: strip router-internal ``mock_testing_*`` flags
from user-supplied data. These are testing-only flags that
deterministically force the router into fallback logic by raising a
synthetic ``InternalServerError`` etc. Combined with override
fallbacks they made the smuggling path trivially exploitable. Test
code that calls the router directly bypasses the strip and is
unaffected. The strip list is derived from ``MockRouterTestingParams``
so a new ``mock_testing_*`` flag added to that dataclass is
automatically covered.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-trust # Conflicts: # tests/test_litellm/proxy/test_route_llm_request.py
CodeQL flagged the previous ``from litellm.types.router import MockRouterTestingParams`` at module top-level — ``litellm.types.router`` indirectly imports back into proxy modules, so the dataclass may not exist yet when ``route_llm_request`` is being imported. Hardcode the three flag names instead, with a guard test (``test_mock_testing_kwarg_names_matches_dataclass``) that asserts the hardcoded list matches ``MockRouterTestingParams.fields`` so drift is caught at test time rather than missed in production. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two related authorization gaps in management endpoints: 1. `/project/update` evaluated permission against the team_id supplied in the request body. By passing `data.team_id` pointing at a team they admin, a caller could hijack any project — `_check_user_permission_for_project` was given the attacker's team_object and happily checked admin membership against that. Drop the team_object kwarg so the helper re-fetches the existing project's team. Also require admin rights on the destination team when reassigning a project across teams, so a team admin cannot shed projects into another team's namespace. 2. `/key/update` accepted any `organization_id` and only checked that the org existed before applying limits. A caller could thereby point their key at an arbitrary org. Add `_validate_caller_can_assign_key_org` which enforces the same membership rule already applied on the `/key/list` filter path (`validate_key_list_check`); proxy admins and no-change updates skip the check. Tests cover both helpers in isolation: existing-team-admin allow, unrelated-team admin deny, proxy-admin shortcut, org-member allow, non-member deny, missing user_id deny, no-memberships deny. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
chore(proxy): tighten router-settings-override and mock-testing trust
Conflict resolution for #26968 dropped the `Iterator` typing import (NameError at module load), left a dead `fallback_models = cast(...)` block, and the new tests called `_enforce_key_and_fallback_model_access` without the now-required `request` kwarg.
…jack fix(proxy): close project hijacking and key org IDOR (VERIA-55)
…te And Regenerate
Mirrors the membership rule on /key/update so that /key/generate and
/key/{key}/regenerate apply the same `_validate_caller_can_assign_key_org`
gate when the caller specifies an `organization_id`. Proxy admins bypass.
The check no-ops when `organization_id` is not being set.
This file is a regenerable UI build artifact that should not be tracked in source. Removing so the merge into litellm_internal_staging stays clean.
Greptile SummaryThis PR patches three distinct authorization gaps (VERIA-44 and VERIA-55): (1) Confidence Score: 4/5Safe to merge; fixes are targeted security patches with good test coverage and no breaking API surface changes. All findings are P2 (style/best-practice). The security logic itself looks correct — permission checks use the right team, all three fallback fields in both request surfaces are covered, and mock_testing flags are stripped. The only improvement noted is that _validate_caller_can_assign_key_org should route through the get_user_object helper rather than making a raw Prisma call. litellm/proxy/management_endpoints/key_management_endpoints.py — the new _validate_caller_can_assign_key_org function makes a direct DB call.
|
| Filename | Overview |
|---|---|
| enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py | Fixes VERIA-55: permission check now uses the project's current team, and team-reassignment requires dual-admin check on both source and destination teams. |
| litellm/proxy/auth/user_api_key_auth.py | Fixes VERIA-44: all three fallback fields (top-level and inside router_settings_override) are now validated against the key's model allowlist; adds iter_router_fallback_model_names helper. |
| litellm/proxy/management_endpoints/key_management_endpoints.py | Adds _validate_caller_can_assign_key_org to enforce org membership on /key/generate, /key/update, and /key/regenerate; direct prisma DB call bypasses existing get_user_object helper. |
| litellm/proxy/route_llm_request.py | Strips router-internal mock_testing_* flags from user-supplied request data before routing, preventing fallback model smuggling (VERIA-44). |
| tests/test_litellm/proxy/auth/test_router_override_fallback_auth.py | New mock-only unit tests covering fallback model validation across all three fallback fields and both top-level and router_settings_override surfaces. |
| tests/test_litellm/proxy/management_endpoints/test_project_org_authz.py | New mock-only unit tests for VERIA-55 covering project permission checks and org-assignment validation. |
| tests/test_litellm/proxy/test_route_llm_request.py | Adds tests verifying mock_testing_* flags are stripped and that _MOCK_TESTING_KWARG_NAMES stays in sync with MockRouterTestingParams dataclass. |
Comments Outside Diff (1)
-
litellm/proxy/management_endpoints/key_management_endpoints.py, line 1226-1229 (link)Direct DB query bypasses
get_user_objecthelper_validate_caller_can_assign_key_orgcallsprisma_client.db.litellm_usertable.find_uniquedirectly rather than routing through the establishedget_user_objecthelper. Per the team's rule on direct DB access in request-handling paths, helper functions should be preferred so caching, tracing, and future schema changes remain centralized. Ifget_user_objectdoesn't yet support aninclude={"organization_memberships": True}option, extending it there would be safer than a one-off direct query here.Rule Used: What: In critical path of request, there should be... (source)
Reviews (1): Last reviewed commit: "[Chore] Proxy/UI: Drop stray _experiment..." | Re-trigger Greptile
[Infra] Merge dev branch
Relevant issues
Linear ticket
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
tests/test_litellm/directory, Adding at least 1 test is a hard requirement - see detailsmake test-unit@greptileaiand received a Confidence Score of at least 4/5 before requesting a maintainer reviewDelays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
CI (LiteLLM team)
Branch creation CI run
Link:
CI run for the last commit
Link:
Merge / cherry-pick CI run
Links:
Screenshots / Proof of Fix
Type
🚄 Infrastructure
Changes