fix(mcp): warn once when use_x_forwarded_for is on but no trusted ranges

Greptile P1: deployments that today have ``use_x_forwarded_for: true``
but never configured ``mcp_trusted_proxy_ranges`` would silently see
their MCP OAuth discovery URLs revert to the proxy's literal bind
address after this change, with no log line explaining why.

Emit a one-shot WARNING the first time the gate denies for that
specific reason, telling the operator exactly which setting to add.
The warning is module-scoped (not per-request) so the proxy log
stays quiet after the first hit.
This commit is contained in:
user
2026-04-30 01:46:42 +00:00
parent 463781d8cb
commit c3fcafb1bf
2 changed files with 60 additions and 0 deletions
+15
View File
@@ -13,6 +13,10 @@ from fastapi import Request
from litellm._logging import verbose_proxy_logger
from litellm.proxy.auth.auth_utils import _get_request_ip_address
# One-shot warning so operators upgrading from the prior "always trust X-Forwarded-*"
# behaviour see an actionable message in their logs the first time it triggers.
_warned_xff_without_trusted_ranges = False
class IPAddressUtils:
"""Static utilities for IP-based MCP access control."""
@@ -144,6 +148,17 @@ class IPAddressUtils:
trusted_ranges = general_settings.get("mcp_trusted_proxy_ranges")
if not trusted_ranges:
global _warned_xff_without_trusted_ranges
if not _warned_xff_without_trusted_ranges:
verbose_proxy_logger.warning(
"use_x_forwarded_for is enabled but mcp_trusted_proxy_ranges "
"is not configured. X-Forwarded-* headers will NOT be "
"trusted, so MCP OAuth discovery URLs will use the proxy's "
"literal base URL. Set mcp_trusted_proxy_ranges in "
"general_settings to your reverse-proxy CIDR(s) to allow "
"X-Forwarded-* through."
)
_warned_xff_without_trusted_ranges = True
return False
direct_ip = request.client.host if request.client else None
@@ -1222,6 +1222,51 @@ def test_get_request_base_url_xff_trust_gate(
assert result == "http://localhost:4000"
def test_xff_misconfig_warning_emitted_once(caplog):
"""Operators upgrading from the old "always trust X-Forwarded-*" behaviour
get a one-shot warning when they have ``use_x_forwarded_for`` enabled
but no ``mcp_trusted_proxy_ranges`` configured. The warning must NOT
spam every request."""
try:
from fastapi import Request
from litellm.proxy import auth as proxy_auth_pkg # noqa: F401
from litellm.proxy._experimental.mcp_server.discoverable_endpoints import (
get_request_base_url,
)
from litellm.proxy.auth import ip_address_utils
except ImportError:
pytest.skip("MCP discoverable endpoints not available")
# Reset the module-level one-shot flag so the test is deterministic.
ip_address_utils._warned_xff_without_trusted_ranges = False
mock_request = MagicMock(spec=Request)
mock_request.base_url = "http://localhost:4000/"
mock_request.client = MagicMock()
mock_request.client.host = "203.0.113.5"
headers = {"X-Forwarded-Host": "attacker.example.com"}
mock_request.headers.get = lambda name, default=None: headers.get(name, default)
misconfig = {"use_x_forwarded_for": True}
import logging
with (
caplog.at_level(logging.WARNING, logger="LiteLLM Proxy"),
patch("litellm.proxy.proxy_server.general_settings", misconfig, create=True),
):
for _ in range(3):
get_request_base_url(mock_request)
matching = [
rec for rec in caplog.records if "mcp_trusted_proxy_ranges" in rec.getMessage()
]
assert (
len(matching) == 1
), f"expected exactly one warning, got {len(matching)}: {[r.getMessage() for r in matching]}"
# -------------------------------------------------------------------
# Tests for scopes_supported when mcp_server.scopes is None
# -------------------------------------------------------------------