Commit graph

38195 commits

Author SHA1 Message Date
user
2c852ba2b1 fix(sso): tighten oauth_state cookie — Secure flag + PKCE-only set
Two Greptile review findings addressed:

1. (P1, security) The ``litellm_oauth_state`` cookie is the sole
   guard against Login-CSRF in the PKCE flow but was set without the
   ``Secure`` attribute, so a network observer on plain HTTP could
   read and replay it — bypassing the protection this PR adds.

   Thread the originating ``Request`` down through
   ``get_sso_login_redirect`` and ``get_generic_sso_redirect_response``
   and set ``Secure`` based on ``request.url.scheme == "https"``.
   When no request is supplied (programmatic callers / tests) default
   to ``Secure=True`` — production-safe.  Local HTTP dev still works
   because the request scheme is observed at runtime.

2. (P2) The cookie was set unconditionally, but the callback only
   validates it inside the PKCE branch.  Two concurrent SSO sessions
   (one PKCE, one plain) could overwrite each other's state cookie
   and produce spurious 400s for the plain-flow user.

   Move the ``set_cookie`` call inside the existing
   ``if code_verifier and "state" in redirect_params`` block so the
   cookie is only written when PKCE is active and the validation
   will actually fire.

Tests cover both paths: PKCE-on (cookie set with Secure default),
PKCE-off (cookie not set), and HTTP dev request (Secure dropped so
the browser will actually attach the cookie on the callback hop).
2026-05-01 00:36:51 +00:00
user
00442e653c chore(sso): bind generic SSO state to a session cookie
The Generic SSO PKCE flow used the URL ``state`` parameter as the
cache key for the PKCE ``code_verifier`` without binding the state
to the caller's browser.  An attacker who pre-minted a state and
cached a verifier under it could hand the resulting login link to a
victim; the victim's auth code would then be exchanged with the
attacker's verifier on the callback, producing an access token
under the attacker's control (Login CSRF / token theft).

The non-PKCE branch is unaffected because it delegates to
fastapi-sso's ``verify_and_process``, which performs its own
session-cookie check.  The PKCE branch bypasses that helper, which
is exactly the gap this commit closes.

Two-part fix in ``ui_sso.py``:

- ``get_generic_sso_redirect_response`` now sets a
  ``litellm_oauth_state`` cookie (HttpOnly, SameSite=Lax, 10-min TTL)
  carrying the state value used in the redirect URL.  The cookie is
  set on the redirect response just like the existing
  ``litellm_cp_return_to`` cookie a few lines earlier in the file.
- ``get_generic_sso_response`` validates ``request.cookies.get(
  "litellm_oauth_state")`` against ``request.query_params.get(
  "state")`` via ``secrets.compare_digest`` before invoking the
  PKCE token exchange.  Mismatch (or either being missing) raises a
  ``ProxyException`` with HTTP 400.

The pre-existing TODO above the redirect logic ("state should be a
random string and added to the user session with cookie") is now
addressed and removed.

Tests cover the redirect-side cookie set, the missing-cookie reject
shape, the URL/cookie-mismatch reject shape, and the matching-cookie
happy path.
2026-05-01 00:19:13 +00:00
yuneng-jiang
bdcc23853c
Merge pull request #26835 from stuxf/codex/cli-sso-flow-binding
chore(cli): tighten CLI SSO session flow
2026-04-30 17:10:27 -07:00
yuneng-jiang
15b7386859
Merge pull request #26815 from stuxf/fix/get-image-lfi-ssrf
chore(proxy): contain UI_LOGO_PATH / LITELLM_FAVICON_URL on unauthenticated asset endpoints
2026-04-30 17:10:15 -07:00
yuneng-jiang
71d5015975
Merge pull request #26827 from stuxf/fix/passthrough-auth-default
chore(passthrough): default auth=True and drop enterprise gate on the safe option
2026-04-30 17:06:37 -07:00
Michael-RZ-Berri
e810d8735d
Merge pull request #26934 from BerriAI/litellm_lazyStartupTestFix
[Fix] Replace subprocess startup-import diff with static source scan
2026-04-30 16:42:52 -07:00
Michael Riad Zaky
47b2832d6f test: replace subprocess startup-import diff with static source scan 2026-04-30 16:15:46 -07:00
yuneng-jiang
256e05e474
Merge pull request #26849 from stuxf/fix/mcp-oauth-discovery-ssrf
chore(mcp): SSRF guard on OAuth metadata discovery follow-up fetches
2026-04-30 13:44:16 -07:00
yuneng-jiang
174c770b07
Merge pull request #26836 from stuxf/fix/byok-credential-encryption
chore(mcp): encrypt user-scoped MCP credentials at rest
2026-04-30 13:42:57 -07:00
yuneng-jiang
4ff8f0e901
Merge pull request #26851 from stuxf/codex/fix-callback-env-secret-resolution
chore(proxy): block env callback refs in key metadata
2026-04-30 13:11:32 -07:00
yuneng-jiang
aa76ab2df7
Merge pull request #26862 from stuxf/codex/control-field-sanitization
chore(proxy): harden request control fields
2026-04-30 13:10:58 -07:00
Michael-RZ-Berri
9637d8c17b
Merge pull request #26802 from BerriAI/litellm_lazyLoadedFrontPage
[Feat / Fix] Lazy loaded imports, lazy loaded front page
2026-04-30 13:04:42 -07:00
yuneng-jiang
08541f49ee
Merge pull request #26910 from BerriAI/litellm_fix/drop-milvus-db-params
fix: drop milvus dbName and partitionNames from MILVUS_OPTIONAL_PARAMS
2026-04-30 12:53:18 -07:00
Yassin Kortam
d84b35cc40
Merge pull request #26906 from BerriAI/litellm_fix/validate-aws-region
fix: validate aws region name
2026-04-30 12:52:31 -07:00
user
51a3e90451 fix(mcp): reuse safe URL fetch for OAuth discovery 2026-04-30 12:42:52 -07:00
yuneng-jiang
3c060364fb
Merge pull request #26840 from stuxf/codex/mcp-oauth-root-visibility
chore(mcp): tighten OAuth root endpoint resolution
2026-04-30 11:59:03 -07:00
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
Yassin Kortam
dfc080f580 fix: drop milvus dbName and partitionNames from MILVUS_OPTIONAL_PARAMS 2026-04-30 11:51:32 -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
user
b67a81da47 test(proxy): align favicon remote asset expectations 2026-04-30 11:46:45 -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
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
user
f48dfdbdd9 fix(proxy): require opt in for audit header fallback 2026-04-30 11:17:04 -07:00
Mateo Wang
609454d0f1
Merge pull request #26852 from BerriAI/litellm_oss_staging
Litellm oss staging
2026-04-30 10:56:05 -07:00
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
ea4e83e066 fix(proxy): keep mcp audit attribution typed 2026-04-30 00:13:34 -07:00
user
697331b534 fix(proxy): apply audit attribution helper consistently 2026-04-30 00:07:43 -07:00
user
db00e674e2 test(proxy): cover control field hardening branches 2026-04-29 23:57:50 -07:00
user
119c70b576 fix(proxy): gate delegated audit attribution 2026-04-29 23:10:14 -07:00
user
7c3c9ab7ef test(proxy): opt mock-response fixtures into client mocks 2026-04-29 23:00:45 -07:00
user
7497674661 fix(proxy): sanitize redaction controls at ingress 2026-04-29 22:52:31 -07:00
user
842eea0131 chore(proxy): harden request control fields 2026-04-29 22:35:17 -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
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
2c11fa0df3 chore(static-assets): keep vault tester out of asset hardening 2026-04-29 20:56:45 -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
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
Cursor Agent
793a35dfe2
test(prometheus): update master-key hash assertions to alias
Some checks failed
Unit Tests: Caching (Redis) / caching-redis (push) Has been cancelled
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Has been cancelled
Unit Tests: Security / security (push) Has been cancelled
Unit Tests: Proxy DB Operations / auth-checks (push) Has been cancelled
Unit Tests: Proxy DB Operations / budgets (push) Has been cancelled
Unit Tests: Proxy DB Operations / custom-logging (push) Has been cancelled
Unit Tests: Proxy DB Operations / db-and-spend (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-runtime (push) Has been cancelled
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Has been cancelled
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Has been cancelled
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Has been cancelled
Unit Tests: Proxy DB Operations / key-generation (push) Has been cancelled
Unit Tests: Proxy DB Operations / logging-misc (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-server-core (push) Has been cancelled
Unit Tests: Proxy DB Operations / schema-migration (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-utils (push) Has been cancelled
PR #26484 substitutes LITELLM_PROXY_MASTER_KEY_ALIAS for
hash_token(master_key) in UserAPIKeyAuth so the master key (or its
hash) never reaches spend logs / metrics. The otel prometheus tests
still hardcoded the SHA-256 of "sk-1234"
("88dc28d0f030c55ed4ab77ed8faf098196cb1c05df778539800c9f1243fe6b4b"),
so the metric labels no longer matched and test_proxy_failure_metrics
failed. Reference the alias constant directly.

https://claude.ai/code/session_01UkzyZKiADEkZDbZFwB98yV

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
2026-04-30 03:09:52 +00: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