Server Implementation
A tool takes a URL argument and fetches it server-side, so an attacker can reach internal services, cloud metadata, or the loopback interface through the MCP process.
SSRF is the bug where the server acts as an open HTTP proxy for whoever can call it. A fetch tool that accepts any URL will happily retrieve `http://169.254.169.254/latest/meta-data/` (AWS IMDS), `http://localhost:6379/` (a neighbouring Redis), or an internal admin panel that trusted its IP-based network boundary. The attack succeeds not because of a parser bug but because the server's *network position* is more privileged than the caller's.
"Fetch this URL" is one of the most commonly-shipped MCP tools — every browse-the-web, read-this-documentation, summarise-this-link server implements it. Those servers run inside VPCs, container networks, or developer laptops with access to private infrastructure the LLM's end-user never intended to expose. Indirect prompt injection can make the LLM issue the SSRF request without the user noticing.
@server.tool() |
def fetch_page(url: str) -> str: |
# No allowlist, no CIDR check — reaches 169.254.169.254, 127.0.0.1, 10.0.0.0/8 |
return requests.get(url, timeout=5).text |
import ipaddress, socket |
from urllib.parse import urlparse |
_BLOCKED = [ipaddress.ip_network(c) for c in |
("127.0.0.0/8", "10.0.0.0/8", "172.16.0.0/12", |
"192.168.0.0/16", "169.254.0.0/16", "::1/128", "fc00::/7")] |
@server.tool() |
def fetch_page(url: str) -> str: |
parsed = urlparse(url) |
if parsed.scheme not in ("http", "https"): |
raise ValueError("only http(s) allowed") |
ip = ipaddress.ip_address(socket.gethostbyname(parsed.hostname)) |
if any(ip in net for net in _BLOCKED): |
raise ValueError("private address not allowed") |
return requests.get(url, timeout=5, allow_redirects=False).text |
We flag HTTP clients (`requests`, `httpx`, `urllib`, `fetch`, `axios`) that take a tool-handler URL parameter without a reserved-CIDR check or an explicit allowlist. `allow_redirects=True` on an unvalidated URL is also flagged because follow-ups re-enable SSRF.
See the full threat catalog for every documented detection.
CVEs of the same CWE class. Not MCP-specific, but exemplify the failure mode MCPSafe detects.
MCPSafe runs this check — and every other rule in the catalog — on any MCP server you paste in.
Scan now