Commit graph

4151 commits

Author SHA1 Message Date
yuneng-jiang
9ea824d5bf
Merge pull request #27143 from BerriAI/cursor/fix-secret-fields-in-spend-logs-a532
fix(security): prevent secret_fields from leaking into spend logs
2026-05-04 19:07:54 -07:00
yuneng-jiang
be5f217aaf
Merge pull request #26861 from BerriAI/litellm_fix_scim_virtual_key_deactivation
fix(scim): revoke virtual keys when SCIM deprovisions a user
2026-05-04 19:03:55 -07:00
Cursor Agent
5923c3209b
fix(security): prevent secret_fields from leaking into spend logs
secret_fields (containing raw HTTP headers including Authorization
Bearer tokens) was being included in proxy_server_request['body']
because the body snapshot was a copy.copy(data) of the full request
dict. This body gets serialized and persisted in the LiteLLM_SpendLogs
table, exposing user credentials in the database.

Root cause: data['secret_fields'] was set before the body snapshot at
data['proxy_server_request']['body'] = copy.copy(data), so the full
raw headers (including auth tokens) ended up in the snapshot.

Fix (defense in depth):
1. Exclude 'secret_fields' when creating the body snapshot in
   litellm_pre_call_utils.py (primary fix)
2. Strip 'secret_fields' in _sanitize_request_body_for_spend_logs_payload
   as a secondary safeguard

secret_fields remains available on the live data dict for legitimate
downstream consumers (MCP, Responses API).

Co-authored-by: Krrish Dholakia <krrish-berri-2@users.noreply.github.com>
2026-05-05 02:01:41 +00:00
user
3dcb6bd3f9
Merge remote-tracking branch 'upstream/litellm_internal_staging' into codex/skills-containers-tenant-guard
# Conflicts:
#	litellm/proxy/auth/auth_utils.py
2026-05-05 01:41:25 +00:00
Yassin Kortam
db2a3cafb6
Merge pull request #27131 from BerriAI/litellm_fix/routing-groups-ui
feat: routing groups ui
2026-05-04 18:16:49 -07:00
Yassin Kortam
a56256e5ee feat: routing groups ui 2026-05-04 18:09:14 -07:00
yuneng-jiang
42cd9493e9
Merge pull request #27071 from stuxf/fix/strip-pricing-fields
chore(proxy): drop client-supplied pricing fields from request bodies
2026-05-04 18:08:41 -07:00
yuneng-jiang
68c120a68f
Merge pull request #26957 from stuxf/chore/guardrail-coverage
chore(guardrails): cover multimodal + Responses-API content shapes
2026-05-04 18:01:27 -07:00
yuneng-jiang
de7175d6ab
Merge pull request #26912 from stuxf/codex/auth-sensitive-routes
chore(proxy): guard sensitive public endpoints
2026-05-04 17:04:10 -07:00
user
abcf204d38 fix(proxy): include request-blocked callback params in auth bans 2026-05-04 16:54:04 -07:00
user
b5a14f22d6
Merge remote-tracking branch 'upstream/litellm_internal_staging' into codex/skills-containers-tenant-guard 2026-05-04 23:50:29 +00:00
user
6a3f6b47de Merge remote-tracking branch 'origin/litellm_internal_staging' into fix/strip-pricing-fields-pr27071
# Conflicts:
#	litellm/proxy/litellm_pre_call_utils.py
2026-05-04 16:45:21 -07:00
user
777862a018
Merge remote-tracking branch 'upstream/litellm_internal_staging' into codex/skills-containers-tenant-guard 2026-05-04 23:40:26 +00:00
yuneng-jiang
0c0b5e005f
Merge pull request #27082 from stuxf/fix/vector-store-cred-leak
fix(vector_store): resolve embedding config at request time, never persist creds
2026-05-04 15:55:40 -07:00
yuneng-jiang
e4ac46b5d1
Merge pull request #27081 from stuxf/fix/strip-callback-fields
chore(proxy): close callback-config and observability-credential side channels
2026-05-04 15:45:42 -07:00
Michael-RZ-Berri
1a17c438b6
Merge pull request #27133 from BerriAI/litellm_zeroBudgetTreatedAsNoCap
[Fix] Treat 0 team_member_budget as no cap
2026-05-04 15:05:18 -07:00
yuneng-jiang
2aa4301fe7
Merge pull request #27027 from stuxf/fix/mcp-server-url-redact-non-admin
fix(proxy): redact MCP server URL and headers for non-admin viewers (VERIA-8)
2026-05-04 15:05:05 -07:00
yuneng-jiang
e1083b1353
Merge pull request #27014 from stuxf/fix/activity-endpoint-tenant-scoping
fix(proxy): scope team and agent activity endpoints per-entity (VERIA-43)
2026-05-04 14:51:45 -07:00
yuneng-jiang
6f5678bcd8
Merge pull request #27007 from stuxf/fix/admin-viewer-write-route-blocklist
fix(auth): block missing write routes for proxy admin viewers
2026-05-04 14:45:14 -07:00
Michael Riad Zaky
28bf4647ef Treat 0 team_member_budget as no cap 2026-05-04 14:45:13 -07:00
yuneng-jiang
e995156462
Merge pull request #26953 from stuxf/chore/audit-log-cache-vault-settings
chore(audit): audit-log /cache/settings + /config_overrides/hashicorp_vault mutations
2026-05-04 14:42:23 -07:00
yuneng-jiang
c38e23e6d3
Merge pull request #26915 from stuxf/codex/provider-url-destination-guard
chore(providers): guard URL-valued model destinations
2026-05-04 14:38:37 -07:00
yuneng-jiang
c064170a18
Merge pull request #26819 from stuxf/fix/team-callback-idor
chore(team): require team-management role on /team/{id}/callback endpoints
2026-05-04 14:31:59 -07:00
user
abbefccad4
fix(guardrails): align banned_keywords + azure_content_safety call_type gates with runtime route_type
The hooks gated on ``call_type == "completion"`` but the proxy ingress
passes ``route_type`` straight through as ``call_type`` —
``"acompletion"`` for /v1/chat/completions and ``"aresponses"`` for
/v1/responses. Tests passed because they used the literal sync
``"completion"`` value, masking the gap.

Switch both hooks to ``is_text_content_call_type`` (matches the
canonical runtime values: completion / acompletion / aresponses) and
update existing tests to assert against runtime values, plus parametrize
a regression test that pins the gate.
2026-05-04 21:27:24 +00:00
harish-berri
f79d3fae2d
Merge pull request #26902 from BerriAI/litellm_pyroscope_tag_wrapper
feat(proxy): add support for Grafana Cloud Pyroscope authentication
2026-05-04 14:08:17 -07:00
harish-berri
ed3b056bc8 Implement normalize_nonempty_secret_str function to trim whitespace from secrets and treat empty values as unset. Update proxy_server to use this function for Grafana credentials. Enhance tests to validate the new normalization behavior. 2026-05-04 18:17:31 +00:00
Mateo Wang
790d8bbe1a
Merge pull request #26899 from BerriAI/litellm_suppress-spend-log-tracebacks-2208
feat(spend-logs): opt-in suppression of stack traces in spend-tracking error logs
2026-05-04 11:09:03 -07:00
harish-berri
a470309c3b Merge branch 'litellm_internal_staging' of https://github.com/BerriAI/litellm into litellm_pyroscope_tag_wrapper
merge parent
2026-05-04 17:17:49 +00:00
Sameer Kankute
32a5e77adf
feat(proxy): add health_check_reasoning_effort for model health checks
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-04 17:13:01 +05:30
user
74b4eab364
fix(vector_store): cache use-time embedding-config resolution
Hold the resolved config in a process-memory TTL cache so the
request-handling path doesn't run litellm_proxymodeltable.find_first
on every vector-store call.
2026-05-03 10:27:53 +00:00
user
38511675b1
fix(vector_store): tighten registry-mutation comment and dedupe test helpers 2026-05-03 10:17:50 +00:00
user
b87c2f66a6
fix(vector_store): resolve embedding config at request time, never persist creds
The vector store create/update path previously called
``_resolve_embedding_config`` against the admin-configured router/DB
model and persisted the resolved ``litellm_embedding_config`` dict
(``api_key`` / ``api_base`` / ``api_version``) into the
``litellm_managedvectorstorestable.litellm_params`` column. Because the
resolver expanded ``os.environ/...`` references via ``get_secret``, the
DB row carried cleartext provider credentials, and the
``/vector_store/{new,info,update,list}`` responses returned them to any
authenticated caller who could supply a known admin model name.

Move the auto-resolve out of ``create_vector_store_in_db`` and out of
the update path. Persist only the user-supplied ``litellm_embedding_model``
reference. Resolve at request-handling time inside
``_update_request_data_with_litellm_managed_vector_store_registry`` so
the resolved config lives in the per-request ``data`` dict and is
garbage-collected after the response. Legacy rows that were created by
an earlier proxy version and already carry a resolved
``litellm_embedding_config`` skip the re-resolution and pass through
unchanged so embedding calls keep working.

The ``new_vector_store`` response now also runs the existing
``_redact_sensitive_litellm_params`` masker (already used by ``info``,
``update``, and ``list``), defending against caller-supplied cleartext
on the create path and against legacy rows whose persisted credentials
are still in the database.

Existing tests that asserted the old write-time-resolve behaviour are
updated to assert the new persistence shape (no embedding config
stored, just the model reference). Two new tests cover the use-time
path: one asserting fresh resolution happens when a row carries only
the model reference, the other asserting legacy rows with persisted
config skip re-resolution and continue to work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 10:08:28 +00:00
user
01323e8903
fix(auth): per-param allow must continue, not return early
A pre-existing logic bug in ``_check_banned_params``: when the
deployment-level ``configurable_clientside_auth_params`` permitted one
banned field, the loop ``return``-ed on the first match instead of
``continue``-ing, so any other banned param later in the same body or
metadata dict was never checked. This PR's metadata walk multiplies the
surface where that bypass matters — a body pairing an allowed
``api_base`` with an observability credential like ``langfuse_host``
would silently pass.

Proxy-wide ``allow_client_side_credentials`` keeps ``return`` (it's a
global opt-in for every banned param). The per-param branch becomes
``continue`` so only the one explicitly-permitted field is skipped.

Adds a regression test that exercises the api_base + langfuse_host pair.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 09:18:17 +00:00
user
37a22acf6f
chore(proxy): close callback-config and observability-credential side channels
Two related gaps in the proxy's request bouncer:

1. ``is_request_body_safe`` (auth_utils.py) walked the request-body root
   and the ``litellm_embedding_config`` nested dict, but not ``metadata``
   or ``litellm_metadata``. The same fields it bans at root — Langfuse /
   Langsmith / Arize / PostHog / Braintrust / Phoenix / W&B Weave / GCS /
   Humanloop / Lunary credentials and routing — were silently accepted
   when the caller put them inside metadata, retargeting observability
   callbacks to a caller-controlled host with caller-supplied creds.
   Walk both metadata containers (and parse the JSON-string form sent via
   multipart / ``extra_body``) through the same banned-params helper, so
   the existing ``allow_client_side_credentials`` opt-in covers both
   paths consistently.

2. The banned-params list was hand-maintained and lagged the canonical
   ``_supported_callback_params`` allow-list in
   ``initialize_dynamic_callback_params``. Derive the observability bans
   from that allow-list (minus a small ``_SAFE_CLIENT_CALLBACK_PARAMS``
   set for informational fields like ``langfuse_prompt_version`` and
   ``langsmith_sampling_rate``) so future integrations are covered
   automatically; ``_EXTRA_BANNED_OBSERVABILITY_PARAMS`` carries the
   handful of fields integrations read but the allow-list hasn't caught
   up to. A guard test fails CI if a new entry is added to
   ``_supported_callback_params`` without an explicit safe-list decision.

Separately in ``litellm_pre_call_utils.py``: add ``callbacks``,
``service_callback``, ``logger_fn``, and ``litellm_disabled_callbacks``
to ``_UNTRUSTED_ROOT_CONTROL_FIELDS``. The first three are appended to
worker-wide ``litellm.{input,success,failure,_async_*,service}_callback``
lists / ``litellm.user_logger_fn`` from inside ``function_setup`` — one
request poisons every subsequent caller in that worker. The last is the
inverse primitive: the legitimate path reads it from key/team metadata,
the request-body version silently disables admin-configured audit /
observability for the call.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 09:06:29 +00:00
user
4b4b4a79b9
fix(proxy): move pricing strip below the litellm_metadata JSON-string parse
The strip ran before the proxy parses ``litellm_metadata`` from a JSON
string into a dict (a path used by multipart/form-data and ``extra_body``
callers), so ``isinstance(metadata, dict)`` was False and ``model_info``
survived the strip. Move the call to the same post-parse position the
``user_api_key_*`` strip already uses for the same reason. Adds a
regression test exercising the JSON-string ``litellm_metadata`` path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 02:04:05 +00:00
user
25671105e2
chore(proxy): log stripped pricing fields at debug for operator visibility
Operators upgrading would otherwise see client-supplied pricing overrides
silently stop applying with no diagnostic. Emit a debug-level line listing
the dropped fields and pointing at the opt-in flag when any are stripped;
stay silent on the no-op path so the log isn't filled with noise.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 01:56:43 +00:00
user
e71aeadea0
chore(proxy): drop client-supplied pricing fields from request bodies
The proxy currently forwards request-body pricing parameters (the fields
on `CustomPricingLiteLLMParams`, plus `metadata.model_info`) into the
core call path. Those fields belong to deployment configuration, not to
per-request input — sending them from a client mutates the request's
recorded cost and, via `litellm.completion` → `register_model`, the
process-wide `litellm.model_cost` map for every later caller in the
worker. Strip them at the boundary.

The strip set is built from `CustomPricingLiteLLMParams.model_fields` so
pricing fields added later are covered automatically. Operators who do
want clients to supply per-request pricing can opt back in per key or
team via `metadata.allow_client_pricing_override = true`, mirroring the
existing `allow_client_mock_response` and
`allow_client_message_redaction_opt_out` flags.

Tests cover the strip set's coverage, root and metadata strips, the
opt-in skip on both key and team metadata, and a regression check that
the global `litellm.model_cost` map is unmutated after a stripped
request.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 01:35:23 +00:00
Sameer Kankute
a5a8f39845
Merge pull request #27036 from BerriAI/litellm_internal_staging
merge main
2026-05-02 11:26:44 +05:30
Sameer Kankute
f576eb3228
Merge pull request #26960 from BerriAI/litellm_org_mcp_permissions
feat(mcp): enforce org-level MCP server and toolset permissions
2026-05-02 11:25:55 +05:30
user
31d0d8599f fix(mcp): redact command fields for non-admin server views 2026-05-01 21:47:18 -07:00
Cursor Agent
8cf3bf11bd
fix(scim): preserve scim_active on PUT when client omits the field
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 / 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-runtime (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
A SCIM PUT may legally omit `active` (full-replace with the field
absent). Pydantic fills the SCIMUser.active default of True, so the PUT
handler was overwriting metadata.scim_active with True even when the
client never sent it — silently reactivating a previously SCIM-blocked
user and unblocking their keys.

Use model_fields_set to detect whether the client actually sent
`active`. If omitted, preserve the prior scim_active value and skip
the cascade to virtual keys.

Also drop comments added in this PR that just narrate what the code
does; keep only the docstrings and the SQL-NULL pitfall note that
explain non-obvious behaviour.

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
2026-05-02 04:15:25 +00:00
mateo-berri
b15136afa7 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_suppress-spend-log-tracebacks-2208 2026-05-01 20:54:52 -07:00
mateo-berri
ea0d92a3d8 fix: remove traceback key instead of it being "" 2026-05-01 20:49:49 -07:00
mateo-berri
456cb495de Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_fix_scim_virtual_key_deactivation 2026-05-01 20:29:19 -07:00
mateo-berri
be4f46683a fix(scim): cascade FK cleanup on user delete and surface block status in UI
SCIM DELETE /Users/{id} previously called litellm_usertable.delete without
clearing rows that FK back to the user, so Postgres rejected the delete with
LiteLLM_InvitationLink_user_id_fkey and the SCIM caller saw a 500. Add a
helper to drop invitation_link, organization_membership, and team_membership
rows before the user delete (mirrors /user/delete in internal_user_endpoints).

Also add a Status column to the Virtual Keys and Internal Users tables so
admins can see at a glance which keys are blocked and which users SCIM has
deactivated. SCIM-blocked keys carry a tooltip explaining the origin.

Pin the dashboard's Node version to 20 via .nvmrc to match CI.
2026-05-01 20:20:39 -07:00
yuneng-jiang
c3f7158b2b
Merge pull request #27008 from stuxf/fix/jwt-audience-and-issuer-verification
Some checks are pending
Unit Tests: Proxy DB Operations / proxy-runtime (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 / key-generation (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / logging-misc (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
Unit Tests: Caching (Redis) / caching-redis (push) Waiting to run
Unit Tests: Proxy DB Operations / assert-shard-coverage (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 / custom-logging (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / db-and-spend (push) Blocked by required conditions
fix(auth): support JWT issuer verification + warn when unscoped
2026-05-01 19:58:52 -07:00
user
6ae589fbb1 fix(proxy): preserve public ai hub ui setting 2026-05-01 19:46:27 -07:00
shin-berri
38ddcdabdb
Merge pull request #27032 from BerriAI/litellm_yj_may1_2
[Infra] Merge dev branch
2026-05-01 19:39:42 -07:00
user
f4e7dde2d8 fix(guardrails): cover multi-choice output variants 2026-05-01 19:38:04 -07:00
user
f909fa79b5 fix(guardrails): close post-call coverage gaps 2026-05-01 19:26:40 -07:00