Skip to content

Worktree fix mcp byok oauth - #27892

Merged
yuneng-berri merged 5 commits into
litellm_internal_stagingfrom
worktree-fix-mcp-byok-oauth
May 14, 2026
Merged

Worktree fix mcp byok oauth#27892
yuneng-berri merged 5 commits into
litellm_internal_stagingfrom
worktree-fix-mcp-byok-oauth

Conversation

@krrish-berri-2

Copy link
Copy Markdown
Contributor

Relevant issues

Linear ticket

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have Added testing in the tests/test_litellm/ directory, Adding at least 1 test is a hard requirement - see details
  • My PR passes all unit tests on make test-unit
  • My PR's scope is as isolated as possible, it only solves 1 specific problem
  • I have requested a Greptile review by commenting @greptileai and received a Confidence Score of at least 4/5 before requesting a maintainer review

Delays 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)

CI status guideline:

  • 50-55 passing tests: main is stable with minor issues.
  • 45-49 passing tests: acceptable but needs attention
  • <= 40 passing tests: unstable; be careful with your merges and assess the risk.
  • Branch creation CI run
    Link:

  • CI run for the last commit
    Link:

  • Merge / cherry-pick CI run
    Links:

Screenshots / Proof of Fix

Type

🆕 New Feature
🐛 Bug Fix
🧹 Refactoring
📖 Documentation
🚄 Infrastructure
✅ Test

Changes

yuneng-berri and others added 5 commits May 7, 2026 18:05
[Infra] Promote Internal Staging to main
[Infra] Promote Internal Staging to main
[Infra] Promote internal staging to main
Authenticated clients could supply CustomPricingLiteLLMParams fields
(input_cost_per_token, output_cost_per_token, etc.) in the request body.
These were forwarded to register_model() in main.py, permanently mutating
the shared global litellm.model_cost dict for all users on the instance.

Adds all CustomPricingLiteLLMParams fields to _BANNED_REQUEST_BODY_PARAMS
so is_request_body_safe() rejects them before they reach completion().
New pricing fields added to CustomPricingLiteLLMParams are auto-covered.

Admin opt-in via allow_client_side_credentials or
configurable_clientside_auth_params still works as before.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
aws_sts_endpoint, aws_web_identity_token, and aws_bedrock_runtime_endpoint
in ingest_options.vector_store were passed directly to the Bedrock ingestion
class, which reads them into boto3 STS client construction. Any authenticated
caller could redirect AssumeRole calls to an attacker-controlled server,
leaking the proxy's instance profile credentials.

Calls is_request_body_safe() on ingest_options["vector_store"] before
forwarding to litellm.aingest(). Same banned-params list and admin opt-in
escape hatch (allow_client_side_credentials) as the /chat/completions path.
ValueError from the safety check is caught and re-raised as HTTP 400.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@CLAassistant

CLAassistant commented May 14, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
2 out of 3 committers have signed the CLA.

✅ yuneng-berri
✅ ryan-crabbe-berri
❌ krrish-berri-2
You have signed the CLA already but the status is still pending? Let us recheck it.

@codecov

codecov Bot commented May 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@greptile-apps

greptile-apps Bot commented May 14, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds two security hardening measures: it blocks pricing-field injection into the global litellm.model_cost registry by adding all CustomPricingLiteLLMParams fields to _BANNED_REQUEST_BODY_PARAMS, and it closes an SSRF vector in the RAG ingest endpoint by calling is_request_body_safe on the vector_store config before forwarding it to litellm.aingest.

  • Pricing injection fix (auth_utils.py): CustomPricingLiteLLMParams.model_fields.keys() is spread into the ban-list at import time, so any field that would mutate the shared cost registry (e.g. input_cost_per_token) is rejected for all users unless the admin explicitly opts in.
  • RAG ingest SSRF guard (endpoints.py): is_request_body_safe is called on ingest_options[\"vector_store\"] before the downstream litellm.aingest call, blocking fields like aws_sts_endpoint that could redirect signed STS calls to attacker-controlled hosts.

Confidence Score: 4/5

Both changes are targeted, security-positive fixes with dedicated tests. The main concerns are the incomplete scope of the SSRF guard and a weak happy-path test assertion.

The core fixes in auth_utils.py and endpoints.py are correct and well-tested. The SSRF guard covers only the vector_store sub-dict, leaving top-level ingest_options keys unchecked, and the happy-path test asserts != 400 so a 500 from an unrelated failure would still pass.

litellm/proxy/rag_endpoints/endpoints.py and tests/test_litellm/proxy/rag_endpoints/test_rag_endpoints.py

Important Files Changed

Filename Overview
litellm/proxy/auth/auth_utils.py Adds all CustomPricingLiteLLMParams fields to _BANNED_REQUEST_BODY_PARAMS at import time, blocking clients from poisoning the global model cost registry via request body injection. Change is minimal and correct.
litellm/proxy/rag_endpoints/endpoints.py Adds is_request_body_safe guard to rag_ingest against SSRF via vector_store config; the check only covers ingest_options vector_store and not the top-level ingest_options dict, leaving a potential gap if banned params are passed at the top level.
tests/test_litellm/proxy/auth/test_auth_utils.py New TestPricingInjectionBlocked class with parametrized per-field rejection tests, a coverage completeness check, and an admin opt-in test. All assertions are specific and meaningful.
tests/test_litellm/proxy/rag_endpoints/test_rag_endpoints.py New TestRagIngestSSRFBlocked class tests SSRF field rejection in the RAG ingest endpoint. The happy-path test uses a weak != 400 assertion that would pass on 500 errors, reducing its value as a regression guard.

Reviews (1): Last reviewed commit: "fix: block SSRF fields in RAG ingest vec..." | Re-trigger Greptile

Comment on lines +191 to +193
assert response.status_code != 400, (
f"Clean Bedrock ingest_options should not be rejected: {response.json()}"
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 The assertion response.status_code != 400 is too weak — it passes if the endpoint returns a 500 (e.g., missing DB config, unrelated server error). The test is meant to prove that clean Bedrock options reach the handler successfully, but a crash masked as a 5xx would still satisfy this condition. Use a positive status assertion instead.

Suggested change
assert response.status_code != 400, (
f"Clean Bedrock ingest_options should not be rejected: {response.json()}"
)
assert response.status_code == 200, (
f"Clean Bedrock ingest_options should be accepted (200), got {response.status_code}: {response.json()}"
)

Comment on lines +474 to +481
is_request_body_safe(
request_body=ingest_options.get("vector_store", {}),
general_settings=general_settings,
llm_router=llm_router,
model="",
)
except ValueError as e:
raise HTTPException(status_code=400, detail={"error": str(e)})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Only vector_store sub-dict is validated

is_request_body_safe is called on ingest_options.get("vector_store", {}), which means banned fields placed directly in ingest_options (e.g. {"aws_sts_endpoint": "...", "vector_store": {...}}) are not checked. If litellm.aingest propagates top-level ingest_options keys into outbound requests, those fields would bypass this guard. Consider passing ingest_options itself as request_body and letting is_request_body_safe's nested-key descent handle vector_store as a nested config key, or additionally calling _check_banned_params on the top-level ingest_options.

@yuneng-berri
yuneng-berri merged commit 0c49820 into litellm_internal_staging May 14, 2026
42 checks passed
@yuneng-berri
yuneng-berri deleted the worktree-fix-mcp-byok-oauth branch May 14, 2026 04:06
yuneng-berri added a commit that referenced this pull request May 14, 2026
fzowl pushed a commit to fzowl/litellm that referenced this pull request Jun 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants