Commit graph

8121 commits

Author SHA1 Message Date
yuneng-jiang
a9db887bdd
Merge pull request #26843 from stuxf/codex/fix-onboarding-invite-token
chore(auth): harden invite-link onboarding token flow
2026-04-30 11:56:26 -07:00
user
c8325ff007 chore(proxy): guard sensitive public endpoints 2026-04-30 11:52:47 -07:00
yuneng-jiang
0efa8b8828
Merge pull request #26854 from stuxf/fix/team-authz-available-team-bypass
chore(team): close authz bypass via the available-team check
2026-04-30 11:47:19 -07:00
yuneng-jiang
d51d96f405
Merge pull request #26859 from stuxf/chore/audit-log-team-callback-mutations
chore(team): audit-log team-callback admin mutations
2026-04-30 11:46:31 -07:00
Cursor Agent
21c7864d75
Fix Vertex label metadata fallback 2026-04-30 18:44:03 +00:00
harish-berri
1b9b918399 Merge branch 'litellm_internal_staging' of https://github.com/BerriAI/litellm into litellm_pyroscope_tag_wrapper 2026-04-30 18:37:09 +00:00
Yassin Kortam
d47948ab23 fix: validate aws region name 2026-04-30 11:35:30 -07:00
user
b8a141cefd fix(static-assets): stop serving stale logo cache 2026-04-30 11:34:25 -07:00
user
215f538d4f fix(static-assets): browser-load remote branding assets 2026-04-30 11:30:57 -07:00
mateo-berri
b5df9d9778
test(vertex_ai): add e2e tests for rerank userLabels propagation
Cover the full litellm.rerank()/arerank() path with HTTP mocked, asserting
metadata.requester_metadata reaches the Discovery Engine :rank body as
userLabels (and stays absent when no metadata is set). Catches plumbing
regressions that unit tests on transform_rerank_request alone would miss.
2026-04-30 18:25:38 +00:00
harish-berri
bde3a98a55 feat(proxy): add support for Grafana Cloud Pyroscope authentication
- Introduced optional environment variables `PYROSCOPE_GRAFANA_USER` and `PYROSCOPE_GRAFANA_API_TOKEN` for Grafana Cloud integration.
- Updated documentation to reflect new configuration options for Pyroscope profiling.
- Enhanced error handling to ensure both credentials are provided when using Grafana Cloud.
- Added tests to validate Grafana Cloud authentication scenarios.
2026-04-30 18:13:03 +00:00
Cursor Agent
2af55422f6
Fix azure container multipart provider assertion 2026-04-30 17:50:01 +00:00
Cursor Agent
3e540e1d81
Fix container file proxy routing 2026-04-30 17:17:39 +00:00
Sameer Kankute
b4f4a931f7
fix(guardrails): log mixed-stream passthrough and cover flush path
Add explicit warnings when Presidio apply_to_output skips masking for mixed/unknown stream event shapes, and add regression coverage for the mixed stream flush path to ensure chunk order is preserved and warnings are emitted.

Made-with: Cursor
2026-04-30 17:08:12 +05:30
Sameer Kankute
5622dd299d
fix(guardrails): preserve responses event streams in presidio output masking
Keep Presidio apply-to-output streaming in passthrough mode when responses-style events are emitted, preventing dropped lifecycle events that caused Codex stream disconnects. Add a regression test to assert unknown streaming events are preserved in order.

Made-with: Cursor
2026-04-30 15:36:00 +05:30
user
09c4d0d01e fix(proxy): gate redaction opt out controls 2026-04-30 00:49:33 -07:00
user
c52be31663 fix(logging): redact standard logging choice metadata 2026-04-30 00:35:29 -07:00
user
db00e674e2 test(proxy): cover control field hardening branches 2026-04-29 23:57:50 -07:00
Yuneng Jiang
00145f91a8
[Fix] RBAC: Default-Allow GET for Admin Viewer + Models Tab Alignment
Root cause: admin_viewer_routes was an explicit allowlist, so every newly-added
GET endpoint anywhere in the codebase silently 403'd for admin viewer until
someone remembered to add it. We had whacked /spend/logs/ui, /customer/list,
/guardrails/list, /policies/attachments/list, /invitation/info, and several
others in serial — but the next round still surfaced /in_product_nudges,
/health/latest, /credentials, /v1/mcp/network/client-ip, /claude-code/plugins,
/policy/templates. This pattern keeps repeating because the model is wrong.

Structural fix in `_check_proxy_admin_viewer_access`:
  - Default-allow safe HTTP methods (GET / HEAD / OPTIONS) on any
    non-inference route. Admin Viewer's principle is read parity with
    Proxy Admin; HTTP semantics already mark GET as side-effect-free, so
    using the method as the allow signal is the correct primitive.
  - Unsafe methods (POST/PUT/PATCH/DELETE) still go through the existing
    explicit allowlists + the hard-blocked write set
    (/user/new, /team/new, /key/generate, …).
  - LLM/inference routes still 403 (cost-incurring).

The existing admin_viewer_routes list is retained as a backstop for the
small set of routes implemented as POST but semantically read (e.g.
/spend/calculate). Adding new GET endpoints no longer requires touching
this list.

Models page tab/panel off-by-one (UI bug for Admin Viewer):
  Tremor's TabList filters falsy children but TabPanels does not, so
  conditionally hiding "Add Model" with `{!shouldHideAddModelTab && ...}`
  left a phantom panel slot — clicking "LLM Credentials" showed nothing,
  and clicking "Pass-Through Endpoints" showed the credentials panel.
  Refactor to a single source-of-truth `visibleTabs` array; tab and
  panel indices now can never desync.

Tests:
  - 12 parametrized tests covering the 6 user-reported endpoints + 4
    hypothetical-future endpoints + 2 already-fixed ones, all asserting
    Admin Viewer GET succeeds via the default-allow path (no allowlist
    entry needed).
  - 5 parametrized tests for POST writes still 403'ing
    (random-future-write, /user/new, /team/new, /key/generate, /model/new).
  - All 207 existing route_checks tests still pass — backward-compatible.
2026-04-29 23:19:45 -07:00
user
7c3c9ab7ef test(proxy): opt mock-response fixtures into client mocks 2026-04-29 23:00:45 -07:00
Yuneng Jiang
2fa6c60124
[Fix] RBAC: Unblock Guardrails / Policies / MCP-filter reads + Keys / Models page hard-blocks
User reported six more 403s and "still restricts access to keys + models" after
the first round. Root causes:

1. Six read endpoints were missing from admin_viewer_routes:
   - /guardrails/list, /v2/guardrails/list (Guardrails page)
   - /guardrails/submissions, /guardrails/submissions/{guardrail_id}
   - /guardrails/usage/overview (Guardrails Monitor page)
   - /policies/attachments/list (Policies page)
   - /get/mcp_semantic_filter_settings (Settings page)

2. /guardrails/submissions handler treated admin viewer as non-admin, filtering
   them to only their team submissions. Switch to _user_has_admin_view() so
   admin viewer sees all submissions (read parity with Proxy Admin).

3. UI Keys page (user_dashboard.tsx) and Models page (ModelsAndEndpointsView.tsx)
   each had a hard "Access Denied" block specifically for "Admin Viewer" — a
   leftover from the pre-parity era. Remove the blocks; gate the "Create Key"
   button on the Keys page so admin viewer can read keys but not mint them.
   Also drop the post-login redirect that forced admin viewers to /usage on
   sign-in (page.tsx).

Tests:
- Extend ADMIN_VIEWER_SETTINGS_ROUTES parametrize list to cover all 7 new
  routes (route-checks layer is now the layer production traffic actually
  hits, vs. the dependency-override-bypass that was masking the gap).
2026-04-29 22:58:38 -07:00
user
7497674661 fix(proxy): sanitize redaction controls at ingress 2026-04-29 22:52:31 -07:00
Cursor Agent
9aef4ee695
fix(scim): treat NULL blocked column as unblocked when deprovisioning
The Prisma schema declares LiteLLM_VerificationToken.blocked as a
nullable Boolean with no default, so virtual keys created via the
key management endpoint persist with blocked=NULL. SQL equality
(`blocked = false`) never matches NULL rows, so the previous
`where={'blocked': not blocked}` filter silently skipped virtually
all real keys when SCIM tried to block them. This made SCIM
deprovisioning a no-op — and especially dangerous in DELETE flows
where the user row is removed afterwards, leaving orphaned but
fully-functional keys.

Match both `False` and `None` when blocking, and only `True`
when unblocking, so the state flip (and cache invalidation) actually
fires for the keys it should.
2026-04-30 05:45:09 +00:00
user
dc3e0739fb test: document gemini file URI handling 2026-04-29 22:38:56 -07:00
user
bf5a8968ba test: avoid provider test module name collision 2026-04-29 22:36:57 -07:00
user
842eea0131 chore(proxy): harden request control fields 2026-04-29 22:35:17 -07:00
user
94c13fe399 fix: cover provider path traversal variants 2026-04-29 22:29:09 -07:00
user
986cdedd4f fix(audit): redact callback secrets and surface fire-and-forget failures
Two Greptile P2s addressed:

1. (security) The audit-log row for an ``add_team_callbacks`` call would
   serialize the entire ``callback_vars`` block — including
   ``langfuse_secret_key``, ``langsmith_api_key``, and the GCS service
   account path — verbatim into ``LiteLLM_AuditLogs``.  Anyone with read
   access to the audit table could harvest team callback credentials.
   Same risk for ``disable_team_logging`` when the team's existing row
   has populated ``callback_settings.callback_vars``.

   Add ``_redact_callback_secrets``: deep-copies the metadata snapshot
   and replaces every ``callback_vars`` value with ``***REDACTED***``.
   The keys are kept so an auditor can still see *which* fields
   changed.  Applied to both before and after snapshots.

2. ``asyncio.create_task`` is fire-and-forget; if the audit-log write
   raises (transient DB error etc.) the exception is silently
   discarded by the event loop and the audit row is just missing —
   the exact gap this PR is closing.  Attach a ``done_callback`` that
   logs the exception at warning level via ``verbose_proxy_logger`` so
   the operator sees there's a gap.

Tests assert that callback values are not present in the serialized
audit payload (both for ``add_team_callbacks`` and for
``disable_team_logging`` when the team's existing row has
populated secrets).
2026-04-30 05:18:29 +00:00
user
124379e42e fix: encode additional provider path identifiers 2026-04-29 22:18:20 -07:00
user
1d7778673a fix: preserve safe provider model path segments 2026-04-29 22:09:54 -07:00
user
adc2c55ffc chore(team): audit-log team-callback admin mutations
The two mutating endpoints in team_callback_endpoints.py
(``/team/{id}/callback`` POST and ``/team/{id}/disable_logging``) wrote
team metadata without emitting an audit-log row.  The disable variant
is the worst case: a logging-control action that itself isn't logged,
so an admin (or compromised admin) could zero out a team's
observability with no forensic trail.

Add ``_emit_team_callback_audit_log`` mirroring the
``store_audit_logs``-gated pattern already used in team_endpoints.py
for /team/new and /team/update.  When ``litellm.store_audit_logs`` is
True, both endpoints now emit an ``LiteLLM_AuditLogs`` row capturing
the calling user, the API key, and the before/after team metadata.
When the flag is False the helper is a no-op, so non-Enterprise
deployments are unaffected.

The ``litellm_changed_by`` header is now also accepted on
``/team/{id}/disable_logging`` to match the existing
``add_team_callbacks`` shape; the header is optional so existing
callers are unaffected.

Variant scope: the file has three endpoints — both mutating variants
are now logged.  The read-only ``GET /team/{id}/callback`` is unchanged.
Other unlogged callback / logging-control admin endpoints elsewhere in
the proxy (e.g. ``/cache/settings``, ``/config_overrides/hashicorp_vault``)
are out of scope here and would be addressed in a separate PR.

Tests cover both endpoints in both ``store_audit_logs`` states and
verify that the captured before/after metadata reflects the actual
mutation, plus that the ``litellm-changed-by`` header overrides the
auth user_id when supplied.
2026-04-30 05:04:49 +00:00
user
d4dd865b1a fix: encode upstream URL path identifiers 2026-04-29 22:02:39 -07:00
user
2f4641752b chore(auth): require trusted proxy for header identity auth 2026-04-29 21:20:21 -07:00
user
09503ebb8f harden budget reservation recovery 2026-04-29 21:06:30 -07:00
user
926de696a1 tighten budget counter cache recovery 2026-04-29 20:51:07 -07:00
Sameer Kankute
50ef2d51a2
Merge pull request #26855 from BerriAI/litellm_internal_staging
merge main
2026-04-30 09:09:45 +05:30
Sameer Kankute
d3891e6eae
Merge pull request #26719 from BerriAI/litellm_fix-bedrock-stream-interrupt-spend-da73
fix(passthrough): track spend for interrupted Bedrock streams
2026-04-30 09:09:08 +05:30
user
72674b06b5 test(team): add /team/permissions_update regression for available-team bypass
Greptile P2: the bypass removal in update_team_member_permissions had
no dedicated regression test.  Adds an integration-style test that
posts to /team/permissions_update as a non-admin caller while
``_is_available_team`` is mocked True, and asserts a 403 — pinning
the bypass-removal against future regressions in the same way the
new member-add unit tests pin the self-join enforcement.
2026-04-30 03:37:41 +00:00
user
5a619cf879 tighten budget spend admission 2026-04-29 20:30:09 -07:00
user
e4c4d9832f chore(team): close authz bypass via the available-team check
Two paths previously treated ``_is_available_team`` as a blanket
authorization bypass — the function was meant to let standard users
self-join a public team but was wired into the broader admin gate
without bounding the action being performed.  Three concrete
exposures resulted:

1. ``/team/member_add``: the bypass let an unprivileged caller add
   themselves as a Team Admin, or add an arbitrary other ``user_id``
   into the team.
2. ``/team/permissions_update``: the same bypass let any authenticated
   user overwrite a team's ``team_member_permissions`` array, mutating
   the access policy for every member.
3. (Read endpoint ``/team/permissions_list`` is unchanged — it leaks
   read-only policy state to non-members but is out of scope of the
   advisory's recommendation; tracking separately.)

This commit:

- Splits ``_validate_team_member_add_permissions`` into early-return
  admin checks followed by an available-team self-join branch that
  enforces ``member.user_id == caller.user_id`` AND
  ``member.role == "user"`` for every member entry in the request.
  The bulk shape (``member: List[Member]``) is checked the same way,
  so a list with one valid self-entry plus one ``role=admin`` entry
  is rejected.  Email-only members are rejected on the self-join
  path: matching by ``user_id`` is the only safe primitive at
  pre-validation time (resolving email→user_id earlier would let
  unauthenticated callers probe user existence).

- Removes the ``_is_available_team`` clause from
  ``update_team_member_permissions`` entirely.  Only proxy / team /
  org admins can update permission policies.

Tests:

- Update the two existing ``_validate_team_member_add_permissions``
  unit tests to pass the new ``data`` argument.
- Add six regression tests covering the privesc shape (role=admin),
  the cross-user-injection shape (other user_id), the no-caller-uid
  fail-closed case, the email-only rejection, and the bulk shape.
- ``test_team_endpoints.py`` 133/133 pass.
2026-04-30 03:23:46 +00:00
Sameer Kankute
26cb28efc5
Merge pull request #26814 from sruthi-sixt-26/fix/bedrock-batch-retrieve
fix(proxy/batches): forward model to retrieve_batch for bedrock
2026-04-30 08:53:23 +05:30
user
1ebb192cbe fix(proxy): catch callback metadata validation errors 2026-04-29 20:13:34 -07:00
user
22c01adeb2 chore(proxy): ignore invalid callback metadata rows 2026-04-29 20:05:35 -07:00
Sameer Kankute
c0211d7d1b
Merge pull request #26759 from BerriAI/litellm_oss_staging
Some checks are pending
Unit Tests: Caching (Redis) / caching-redis (push) Waiting to run
Unit Tests: Proxy DB Operations / auth-checks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / budgets (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / key-generation (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Waiting to run
Unit Tests: Proxy DB Operations / custom-logging (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / db-and-spend (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / logging-misc (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-runtime (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / schema-migration (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
Unit Tests: Security / security (push) Waiting to run
Litellm oss staging
2026-04-30 08:35:30 +05:30
Sameer Kankute
6588564a88
Merge pull request #26691 from BerriAI/litellm_team_search_credentials_metadata
feat(proxy): add team-level search provider credentials
2026-04-30 08:35:17 +05:30
Sameer Kankute
ff24d2a025
Merge pull request #26800 from BerriAI/litellm_bedrock-anthropic-1hr-cache-pricing-2db1
fix(bedrock): add 1-hour cache write pricing for Claude 4.5/4.6/4.7 (Global, US)
2026-04-30 08:31:09 +05:30
user
1bb04cdc72 fix(mcp): close redirect bypass + empty-getaddrinfo gap on SSRF guard
Three follow-ups to the OAuth-discovery SSRF guard:

1. Greptile P1 (redirect bypass): the validated origin could return a
   3xx whose ``Location`` points at an internal address, and httpx
   would follow without re-checking the new target.  Pass
   ``follow_redirects=False`` to both gated httpx GETs.  Spec-compliant
   OAuth/OIDC metadata endpoints serve the JSON directly, so this
   doesn't affect legitimate providers.

2. Greptile P2 (empty getaddrinfo): POSIX doesn't strictly forbid an
   empty success-list from ``getaddrinfo``.  Add an explicit
   ``if not infos: return False`` so the guard fails closed instead of
   falling through to ``return True``.

3. Mypy: ``info[4][0]`` is typed ``str | int``; narrow at the
   boundary with an ``isinstance`` check (fail-closed if non-str).

Adds two regression tests verifying ``follow_redirects=False`` is
passed at both gated fetch sites, and one verifying the empty-list
case rejects the URL.
2026-04-30 02:59:50 +00:00
user
4d056a1f01 test(proxy): cover callback env metadata rejection 2026-04-29 19:56:37 -07:00
ryan-crabbe-berri
b1b98c3fc7
Merge pull request #26821 from BerriAI/litellm_fix-guardrail-auth-check
fix(proxy/auth): tighten guardrail modification permission check
2026-04-29 19:48:34 -07:00
ryan-crabbe-berri
7c8e95888a
Merge pull request #26831 from BerriAI/litellm_fix-passthrough-batch-identity
fix(proxy): inherit caller identity in passthrough batch managed-object
2026-04-29 19:48:26 -07:00