Skip to content

fix(mcp): correct misleading no-trusted-proxy warning for XFF access control - #31264

Merged
mateo-berri merged 2 commits into
litellm_internal_stagingfrom
litellm_fix_mcp_xff_no_trusted_ranges_warning
Jun 25, 2026
Merged

fix(mcp): correct misleading no-trusted-proxy warning for XFF access control#31264
mateo-berri merged 2 commits into
litellm_internal_stagingfrom
litellm_fix_mcp_xff_no_trusted_ranges_warning

Conversation

@mateo-berri

@mateo-berri mateo-berri commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Relevant issues

N/A

Linear ticket

N/A

Pre-Submission checklist

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

  • I have added meaningful tests
  • 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

Type

🐛 Bug Fix

Changes

IPAddressUtils.is_request_from_trusted_proxy in litellm/proxy/auth/ip_address_utils.py logs a one-shot warning when use_x_forwarded_for is enabled but mcp_trusted_proxy_ranges is unset. The previous wording claimed that in this state both MCP OAuth discovery URLs and access-control client IPs "will use the proxy's literal request values," which is only half true and misleads operators about the security posture

The method has two consumers that diverge in this exact configuration. get_request_base_url in litellm/proxy/_experimental/mcp_server/oauth_utils.py does fall back to the request's literal base URL for OAuth discovery and redirect_uri construction, so that half was accurate. get_mcp_client_ip in the same ip_address_utils.py file does the opposite: when XFF is enabled, an x-forwarded-for header is present, and mcp_trusted_proxy_ranges is unset, it does not return any literal request value. It fails closed and returns "", so the caller is treated as external and only sees servers with available_on_public_internet=true. The old message told operators their access-control client IPs would use literal request values, which would have led them to believe internal callers behind an untrusted proxy still resolve to their real IP when they actually get classified as external

This PR rewords the warning so it describes both behaviors accurately: OAuth discovery URLs fall back to the literal request URL, and access-control client-IP resolution fails closed with callers treated as external. No behavior changes; the message text is the only source change

The added regression test ties the message to the real behavior. It triggers the branch with use_x_forwarded_for on, an x-forwarded-for header present, and mcp_trusted_proxy_ranges unset, captures the warning via caplog, asserts the new fail-closed phrasing is present and the old misleading claim is gone, and asserts in the same scenario that get_mcp_client_ip returns "". Reverting the wording makes the assertions fail, and the coupled get_mcp_client_ip assert keeps the message honest about reality

Screenshots / Proof of Fix

Ran a local proxy with use_x_forwarded_for: true and no mcp_trusted_proxy_ranges, then hit an MCP REST route that resolves the client IP with an X-Forwarded-For header. The corrected warning shows up in the proxy log

Start (config has general_settings.use_x_forwarded_for: true, an mcp_servers block, and crucially no mcp_trusted_proxy_ranges):

FORWARDED_ALLOW_IPS=10.255.255.255 python litellm/proxy/proxy_cli.py --config /tmp/xff_warn_config.yaml --detailed_debug 2>&1 | tee /tmp/xff_warn.log

Trigger:

$ curl -s -w "\nHTTP %{http_code}\n" -H 'x-forwarded-for: 1.2.3.4, 10.0.0.1' -H 'Authorization: Bearer sk-1234' http://localhost:4000/mcp-rest/tools/list
{"tools":[],"error":null,"message":"Successfully retrieved tools"}
HTTP 200

Corrected warning grep'd from the log:

$ grep -F "mcp_trusted_proxy_ranges" /tmp/xff_warn.log | grep -F "fails closed"
19:40:17 - LiteLLM Proxy:WARNING: ip_address_utils.py:153 - use_x_forwarded_for is enabled but mcp_trusted_proxy_ranges is not configured, so X-Forwarded-* headers will NOT be trusted. MCP OAuth discovery URLs fall back to the proxy's literal request URL, and MCP access-control client-IP resolution fails closed (callers are treated as external). Set mcp_trusted_proxy_ranges in general_settings to your reverse-proxy CIDR(s) to trust X-Forwarded-*.

Note

Low Risk
Log message and test-only change; MCP IP trust and access-control behavior are unchanged.

Overview
Updates the one-shot proxy log warning when use_x_forwarded_for is on but mcp_trusted_proxy_ranges is unset. The old text implied MCP access-control client IPs would use the proxy’s literal request values; that was wrong for get_mcp_client_ip, which already fails closed ("", callers treated as external) while OAuth discovery can still fall back to the literal request URL.

The new wording states both outcomes explicitly and still points operators at mcp_trusted_proxy_ranges. No runtime behavior changes.

Adds test_no_trusted_ranges_warning_matches_fail_closed_behavior, which captures the warning via caplog, checks for the fail-closed phrasing and absence of the old line, and asserts get_mcp_client_ip returns "" in the same setup.

Reviewed by Cursor Bugbot for commit d2d26ec. Bugbot is set up for automated code reviews on this repo. Configure here.

@greptile-apps

greptile-apps Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR corrects the one-shot warning emitted by IPAddressUtils.is_request_from_trusted_proxy when use_x_forwarded_for is enabled without mcp_trusted_proxy_ranges configured, replacing misleading text that implied client IPs would resolve to literal request values with accurate text describing the two diverging behaviors.

  • The warning now distinguishes the two callers: OAuth discovery URL construction falls back to the literal request URL, while client-IP resolution fails closed and treats callers as external — the latter behavior is what the old message got wrong.
  • A new regression test resets the module-level one-shot flag, captures the warning with caplog, asserts both the updated phrasing and the absence of the old misleading claim, and independently verifies that get_mcp_client_ip returns "" in the same configuration to keep the message honest about the actual behavior.

Confidence Score: 5/5

Safe to merge — only the warning message text changes; all runtime behavior is identical to the base branch.

The production change is confined to a single string literal inside a one-shot logging call. No control flow, no data processing, and no auth decisions are touched. The accompanying test resets the relevant global flag, exercises the exact branch under test, and makes assertions that would catch a revert of the message change.

No files require special attention.

Important Files Changed

Filename Overview
litellm/proxy/auth/ip_address_utils.py Warning message text updated to accurately describe both fail-closed behaviors; no logic changes.
tests/test_litellm/proxy/auth/test_mcp_ip_filtering.py New regression test added that resets the one-shot flag, captures the warning via caplog, asserts the updated phrasing, and validates the actual fail-closed return value of get_mcp_client_ip.

Reviews (2): Last reviewed commit: "test(mcp): assert the no-trusted-ranges ..." | Re-trigger Greptile

Comment thread tests/test_litellm/proxy/auth/test_mcp_ip_filtering.py
@codecov

codecov Bot commented Jun 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit d2d26ec. Configure here.

@mateo-berri
mateo-berri requested a review from tin-berri June 25, 2026 03:29
@mateo-berri
mateo-berri merged commit 257d671 into litellm_internal_staging Jun 25, 2026
151 of 152 checks passed
@mateo-berri
mateo-berri deleted the litellm_fix_mcp_xff_no_trusted_ranges_warning branch June 25, 2026 03:49
ishaan-berri pushed a commit to ishaan-berri/litellm that referenced this pull request Jun 25, 2026
…control (BerriAI#31264)

* fix(mcp): correct misleading no-trusted-proxy warning for XFF access control

* test(mcp): assert the no-trusted-ranges warning was logged instead of relying on StopIteration
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.

2 participants