CVE-2026-116686:MCP Python SDK 外部 $ref 解析漏洞可觸發 SSRF 與同步 DoS
CVE-2026-116686: CVE-2026-116686: Server-Side Request Forgery and Synchronous Denial of Service in Model Context Protocol…
CVE-2026-116686 涉及 MCP Python SDK:客戶端驗證工具結果時會解析伺服器提供的外部 $ref,惡意 MCP 伺服器可藉此觸發盲 SSRF、探測本機檔案,或同步阻塞事件迴圈。
CVE-2026-116686: Server-Side Request Forgery and Synchronous Denial of Service in Model Context Protocol Python SDK
Vulnerability ID: CVE-2026-116686
CVSS Score: 6.5
Published: 2026-10-27
CVE-2026-116686 is a Server-Side Request Forgery (SSRF) and Denial of Service (DoS) vulnerability in the official Model Context Protocol (MCP) Python SDK (mcp package on PyPI). When an MCP client validates structured tool execution results against a server-provided outputSchema, the SDK invokes the Python jsonschema library with its default URI resolution configuration. An untrusted or compromised MCP server can supply an outputSchema containing external $ref directives (using http://, https://, or file:// schemes), forcing the client process to synchronously fetch internal network resources, read local files, or block the main event loop indefinitely.
TL;DR
The Model Context Protocol (MCP) Python SDK (versions 1.10.0 to 1.29.1 and 2.0.0 to 2.1.1) resolves external $ref URIs when validating tool results against server-supplied output schemas. Connecting to a malicious MCP server and calling a tool allows the server to trigger blind SSRF, probe local files, or freeze the client application's asynchronous event loop via synchronous network requests without timeouts. Upgrade to mcp 1.30.0 or 2.2.0 to restrict schema resolution to in-document references.
⚠️ Exploit Status: POC
Technical Details
- Vulnerability Type: CWE-918: Server-Side Request Forgery (SSRF) & Synchronous Event-Loop DoS
- CVSS v3.1 Score: 6.5 Medium (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H)
- Affected Package: mcp (PyPI) >= 1.10.0, < 1.30.0 and >= 2.0.0, < 2.2.0
- Patched Versions: mcp 1.30.0 (v1.x) and mcp 2.2.0 (v2.x)
- Affected Component: src/mcp/client/session.py (validate_tool_result / _validate_tool_result)
- Attack Vector: Network (Untrusted MCP Server returning crafted Tool.outputSchema)
- Primary Impact: Blind SSRF, Local File Probing (file://), Process-wide Event Loop Freezing
- CISA KEV Status: Not Listed
Affected Systems
- Model Context Protocol Python SDK (PyPI: mcp) >= 1.10.0, < 1.30.0
- Model Context Protocol Python SDK (PyPI: mcp) >= 2.0.0, < 2.2.0
-
mcp (Model Context Protocol Python SDK): >= 1.10.0, < 1.30.0 (Fixed in:
1.30.0) -
mcp (Model Context Protocol Python SDK): >= 2.0.0, < 2.2.0 (Fixed in:
2.2.0)
Code Analysis
Commit: 6705402
Resolve tool output-schema references within the schema document only (#3394)
--- a/src/mcp/client/session.py
+++ b/src/mcp/client/session.py
@@ -1126,7 +1126,8 @@ async def validate_tool_result(self, name: str, result: types.CallToolResult) ->
"""Revalidate a `CallToolResult` against the tool's declared output schema.
Raises:
- RuntimeError: Structured content is missing or does not conform to the schema.
+ RuntimeError: Structured content is missing or does not conform to the schema, or the
+ schema is invalid or has a `$ref` that does not resolve within the schema document.
"""
if name not in self._tool_output_schemas:
# refresh output schema cache
@@ -1140,17 +1141,22 @@ async def validate_tool_result(self, name: str, result: types.CallToolResult) ->
if output_schema is not None:
from jsonschema import exceptions as jsonschema_exceptions
+ from referencing.exceptions import Unresolvable
if result.structured_content is None:
raise RuntimeError(f"Tool {name} has an output schema but did not return structured content")
validator = self._output_schema_validator(name, output_schema)
# `best_match` picks the same error the previous `jsonschema.validate()` call raised,
# so the message a caller sees is unchanged. It is untyped upstream.
errors = validator.iter_errors(result.structured_content)
- error = cast(
- "Exception | None",
- jsonschema_exceptions.best_match(errors), # pyright: ignore[reportUnknownMemberType]
- )
+ try:
+ error = cast(
+ "Exception | None",
+ jsonschema_exceptions.best_match(errors), # pyright: ignore[reportUnknownMemberType]
+ )
+ except Unresolvable as e:
+ # A `$ref` did not resolve within the schema document.
+ raise RuntimeError(f"Invalid schema for tool {name}: {e}") from e
if error is not None:
raise RuntimeError(f"Invalid structured content returned by tool {name}: {error}") from error
@@ -1168,6 +1174,7 @@ def _output_schema_validator(self, name: str, output_schema: dict[str, Any]) ->
"""
from jsonschema import SchemaError
from jsonschema.validators import validator_for
+ from referencing import Registry
if (validator := self._tool_output_validators.get(name)) is not None:
return validator
@@ -1177,9 +1184,8 @@ def _output_schema_validator(self, name: str, output_schema: dict[str, Any]) ->
validator_cls.check_schema(output_schema)
except SchemaError as e:
raise RuntimeError(f"Invalid schema for tool {name}: {e}")
- # jsonschema ships no `py.typed`, so pyright reads typeshed's stub, which declares
- # `registry` as required (concrete validators default it); cast to a schema-only ctor.
- validator = cast("Callable[[dict[str, Any]], Validator]", validator_cls)(output_schema)
+ # An explicit empty registry: `$ref`s resolve within the schema document and the bundled metaschemas.
+ validator = validator_cls(output_schema, registry=Registry())
self._tool_output_validators[name] = validator
return validator
Commit: 5ebdfed
[v1.x] Resolve tool output-schema references within the schema document only (#3396)
--- a/src/mcp/client/session.py
+++ b/src/mcp/client/session.py
@@ -428,17 +428,24 @@ async def _validate_tool_result(self, name: str, result: types.CallToolResult) -
if output_schema is not None:
from jsonschema import SchemaError, ValidationError, validate
+ from referencing import Registry
+ from referencing.exceptions import Unresolvable
if result.structuredContent is None:
raise RuntimeError(
f"Tool {name} has an output schema but did not return structured content"
) # pragma: no cover
+ # An explicit empty registry: `$ref`s resolve within the schema document and the bundled metaschemas.
+ registry: Registry[Any] = Registry()
try:
- validate(result.structuredContent, output_schema)
+ validate(result.structuredContent, output_schema, registry=registry)
except ValidationError as e:
raise RuntimeError(f"Invalid structured content returned by tool {name}: {e}") # pragma: no cover
except SchemaError as e: # pragma: no cover
raise RuntimeError(f"Invalid schema for tool {name}: {e}") # pragma: no cover
+ except Unresolvable as e:
+ # A `$ref` did not resolve within the schema document.
+ raise RuntimeError(f"Invalid schema for tool {name}: {e}") from e
Mitigation Strategies
- Upgrade the mcp Python SDK to version 1.30.0 (for 1.x environments) or 2.2.0 (for 2.x environments) to enforce isolated in-memory JSON Schema reference resolution.
- Restrict MCP client connections exclusively to vetted, trusted MCP servers until the SDK upgrade is deployed.
- Implement client-side schema sanitization middleware to inspect Tool.outputSchema definitions and block any tool containing $id attributes or non-fragment $ref / $dynamicRef URIs (URIs not starting with '#').
- Apply network egress filtering on hosts running MCP clients to block unauthorized connections to link-local cloud metadata services (169.254.169.254) and internal intranet subnets.
Remediation Steps:
- Audit Python environments and dependency lockfiles (requirements.txt, poetry.lock, uv.lock) for the presence of the 'mcp' package in versions >= 1.10.0, < 1.30.0 or >= 2.0.0, < 2.2.0.
- Run 'pip install --upgrade "mcp>=1.30.0,<2.0.0"' for 1.x deployments or 'pip install --upgrade "mcp>=2.2.0"' for 2.x deployments.
- Verify the installed package version by executing: python -c "import mcp; print(getattr(mcp, 'version', 'unknown'))".
- Ensure existing MCP server tool schemas do not rely on external HTTP/HTTPS $ref resolution, as patched clients will raise a RuntimeError when encountering external schema references.
References
- GitHub Security Advisory GHSA-rwrf-2pqf-9j8j
- Official CVE Record (CVE-2026-116686)
- GitHub Commit 6705402e246dc4eb1fcdf4d9902b78d3c9c36e1b (v2.x Patch)
- GitHub Commit 5ebdfed4060d8e5b11b8e2348f86bad4d1fb8836 (v1.x Patch)
- GitHub Pull Request #3394 (v2.x Fix)
- GitHub Pull Request #3396 (v1.x Fix)
- Model Context Protocol Python SDK Release v1.30.0
- Model Context Protocol Python SDK Release v2.2.0
Read the full report for CVE-2026-116686 on our website for more details including interactive diagrams and full exploit analysis.
來源:DEV Community · dev.to