Skip to content

Commit 69fe96c

Browse files
committed
fix: improve allowed host validation to handle ports correctly
>> >> - Added proper host and port parsing without using urlparse >> - Normalized incoming host by removing protocol and path >> - Updated allowed host matching logic with clear rules: >> >> 1. host (example.com) >> - allows requests from the host with or without ports >> >> 2. host:* (example.com:*) >> - explicitly allows any port for that host >> >> 3. host:port (example.com:443) >> - allows only the exact specified port >> >> - Prevented incorrect matches when specific ports are configured >> - Improved transport security host validation consistency >> - Keeps logic compatible with proxy environments (e.g. Heroku) >> >> This fixes cases where: >> - hosts without ports were incorrectly rejected >> - port-specific allowed hosts did not enforce strict matching
1 parent 688c6e3 commit 69fe96c

File tree

1 file changed

+42
-7
lines changed

1 file changed

+42
-7
lines changed

src/mcp/server/transport_security.py

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,55 @@ def _validate_host(self, host: str | None) -> bool: # pragma: no cover
4747
return False
4848

4949
# Check exact match first
50+
print(host)
5051
if host in self.settings.allowed_hosts:
5152
return True
52-
53-
# Check wildcard port patterns
53+
5454
for allowed in self.settings.allowed_hosts:
55+
56+
# normalize incoming host
57+
host_without_https = (
58+
host.replace("https://", "")
59+
.replace("http://", "")
60+
.split("/")[0]
61+
.strip()
62+
)
63+
64+
# split request host + port
65+
if ":" in host_without_https:
66+
request_host, request_port = host_without_https.split(":", 1)
67+
else:
68+
request_host = host_without_https
69+
request_port = None
70+
71+
# ---------- CASE 1: wildcard port (example.com:*) ----------
5572
if allowed.endswith(":*"):
56-
# Extract base host from pattern
5773
base_host = allowed[:-2]
58-
# Check if the actual host starts with base host and has a port
59-
if host.startswith(base_host + ":"):
74+
print(base_host)
75+
76+
if request_host == base_host:
6077
return True
61-
78+
79+
# ---------- CASE 2: specific port (example.com:443) ----------
80+
elif ":" in allowed:
81+
allowed_host, allowed_port = allowed.split(":", 1)
82+
83+
if (
84+
request_host == allowed_host
85+
and request_port == allowed_port
86+
):
87+
return True
88+
89+
# ---------- CASE 3: host only (allow any port) ----------
90+
else:
91+
if request_host == allowed:
92+
return True
93+
94+
logger.warning(f"Invalid Host header: {host}")
95+
return False
96+
6297
logger.warning(f"Invalid Host header: {host}")
63-
return False
98+
return False
6499

65100
def _validate_origin(self, origin: str | None) -> bool: # pragma: no cover
66101
"""Validate the Origin header against allowed values."""

0 commit comments

Comments
 (0)