Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions litellm/proxy/auth/ip_address_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,12 @@ def is_request_from_trusted_proxy(
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 and access-control "
"client IPs will use the proxy's literal request values. "
"Set mcp_trusted_proxy_ranges in "
"general_settings to your reverse-proxy CIDR(s) to allow "
"X-Forwarded-* through."
"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-*."
)
_warned_xff_without_trusted_ranges = True
return False
Expand Down
41 changes: 41 additions & 0 deletions tests/test_litellm/proxy/auth/test_mcp_ip_filtering.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
external callers only see servers with available_on_public_internet=True.
"""

import logging
from unittest.mock import MagicMock, patch

from fastapi import Request

import litellm.proxy.auth.ip_address_utils as ip_mod
from litellm._logging import verbose_proxy_logger
from litellm.proxy.auth.ip_address_utils import IPAddressUtils
from litellm.types.mcp_server.mcp_server_manager import MCPServer

Expand Down Expand Up @@ -77,6 +80,44 @@ def test_fails_closed_when_xff_enabled_without_trusted_proxy_ranges(self):
assert result == ""
assert IPAddressUtils.is_internal_ip(result) is False

def test_no_trusted_ranges_warning_matches_fail_closed_behavior(self, caplog):
ip_mod._warned_xff_without_trusted_ranges = False

request = MagicMock(spec=Request)
request.client = MagicMock()
request.client.host = "203.0.113.5"
request.headers = {"x-forwarded-for": "1.2.3.4, 10.0.0.1"}
general_settings = {"use_x_forwarded_for": True}

with caplog.at_level(logging.WARNING, logger=verbose_proxy_logger.name):
assert (
IPAddressUtils.is_request_from_trusted_proxy(
request, general_settings=general_settings
)
is False
)

warning = next(
(
record.getMessage()
for record in caplog.records
if "mcp_trusted_proxy_ranges" in record.getMessage()
),
None,
)
Comment thread
greptile-apps[bot] marked this conversation as resolved.
assert (
warning is not None
), "Expected a warning containing 'mcp_trusted_proxy_ranges' but none was logged"

assert "fails closed" in warning
assert "treated as external" in warning
assert "client IPs will use the proxy's literal request values" not in warning

assert (
IPAddressUtils.get_mcp_client_ip(request, general_settings=general_settings)
== ""
)

def test_private_proxy_peer_does_not_grant_internal_access(self):
# Regression: behind an internal reverse proxy with use_x_forwarded_for
# enabled but mcp_trusted_proxy_ranges unset, the direct peer is the
Expand Down
Loading