From a6492bf424d559e741a5685f54c6ab3997b4a422 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 20 May 2026 16:59:07 +0000 Subject: [PATCH] fix(auth): address remaining greptile style findings - get_request_route: require root_path to match whole path segments before stripping, so '/apifoo' isn't truncated to 'foo' when root_path='/api'. - get_mcp_client_ip: collapse the two trusted-proxy validation branches into a single is_request_from_trusted_proxy call so the return value drives control flow instead of being discarded for the side-effect warning. Co-authored-by: Claude --- litellm/proxy/auth/auth_utils.py | 12 +++++++----- litellm/proxy/auth/ip_address_utils.py | 26 ++++++++++---------------- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/litellm/proxy/auth/auth_utils.py b/litellm/proxy/auth/auth_utils.py index 44266203446..4f83fe570b5 100644 --- a/litellm/proxy/auth/auth_utils.py +++ b/litellm/proxy/auth/auth_utils.py @@ -511,11 +511,13 @@ def get_request_route(request: Request) -> str: ).rstrip("/") if not isinstance(raw_path, str): return str(request.url.path) - # Only strip root_path when it is a meaningful prefix. Trailing - # slashes are stripped above so the result always keeps its leading - # "/" — stripping a bare "/" or "/prefix/" would otherwise produce - # paths like "team/new" and break route matching. - if root_path and raw_path.startswith(root_path): + # Strip root_path only when it matches whole path segments — guarding + # against sibling paths like "/apifoo" being truncated under + # root_path="/api". Trailing slashes on root_path are stripped above, + # so bare "/" or "/prefix/" still leave the leading "/" intact. + if root_path and ( + raw_path == root_path or raw_path.startswith(root_path + "/") + ): return raw_path[len(root_path) :] return raw_path except Exception as e: diff --git a/litellm/proxy/auth/ip_address_utils.py b/litellm/proxy/auth/ip_address_utils.py index 0218bc2211a..ff5fb985ceb 100644 --- a/litellm/proxy/auth/ip_address_utils.py +++ b/litellm/proxy/auth/ip_address_utils.py @@ -200,21 +200,15 @@ class IPAddressUtils: # If XFF is enabled, validate the request comes from a trusted proxy if use_xff and "x-forwarded-for" in request.headers: - trusted_ranges = general_settings.get("mcp_trusted_proxy_ranges") - if not trusted_ranges: - IPAddressUtils.is_request_from_trusted_proxy( - request, general_settings=general_settings - ) + if not IPAddressUtils.is_request_from_trusted_proxy( + request, general_settings=general_settings + ): + direct_ip = request.client.host if request.client else None + if general_settings.get("mcp_trusted_proxy_ranges"): + # Direct connection isn't in any configured trusted CIDR. + verbose_proxy_logger.warning( + "XFF header from untrusted IP %s, ignoring", direct_ip + ) + return direct_ip return _get_request_ip_address(request, use_x_forwarded_for=False) - # Validate direct connection is from trusted proxy - direct_ip = request.client.host if request.client else None - trusted_networks = IPAddressUtils.parse_trusted_proxy_networks( - trusted_ranges - ) - if not IPAddressUtils.is_trusted_proxy(direct_ip, trusted_networks): - # Untrusted source trying to set XFF - ignore XFF, use direct IP - verbose_proxy_logger.warning( - "XFF header from untrusted IP %s, ignoring", direct_ip - ) - return direct_ip return _get_request_ip_address(request, use_x_forwarded_for=use_xff)