CVE-2026-52870: MCP Python SDK: Experimental task handlers allow any client to access and cancel other clients' tasks
In the MCP Python SDK (`mcp` 1.23.0 through 1.27.1), the default handlers behind `server.experimental.enable_tasks()` do not check which session created a task. On a multi-client server, any connected client can list, read and cancel other clients' tasks. Servers that never enable the experimental tasks feature are not affected. Upgrade to mcp 1.27.2.
Published Jul 16, 2026 · Analysis Oct 25, 2026
What an attacker can do
Enabling tasks registers default handlers for tasks/list, tasks/get, tasks/result and tasks/cancel. They work on the task ID alone and keep no record of the creating session. Because tasks/list returns every task in the store, an attacker does not need to know any ID. They enumerate all tasks, then read each one's status and result with tasks/get and tasks/result.
The flaw also reaches queued task messages. Elicitation requests meant for the task's creator are removed from the queue on delivery, so if another client pulls them first, the real recipient never gets them. The attacker can also cancel any task with tasks/cancel.
The attacker needs to be a connected, authenticated client (PR:L) on a server shared by several clients. The result is disclosure of other clients' task output and elicitation payloads, loss of those messages, and disruption of their running work. Servers that register their own task handlers are exposed only if those handlers have the same missing check.
Who is affected
PyPI package mcp from 1.23.0 through 1.27.1, and only when the server calls server.experimental.enable_tasks() and serves more than one client. To see if you use it, search your code:
grep -r enable_tasks .If nothing matches, the application is not affected. Check the installed SDK version:
pip show mcpmcp
- Ecosystem
- PyPI
- Affected
- >= 1.23.0, <= 1.27.1
- Fixed in
- 1.27.2
- Check
pip show mcp
How to fix it
Upgrade to mcp 1.27.2:
pip install --upgrade mcp==1.27.2In that release, run_task() puts an opaque per-session marker in task IDs. The default handlers answer "task not found" for another session's task, and tasks/list returns only the caller's tasks. Tasks created with explicitly chosen IDs, or written straight to a TaskStore, are still reachable by ID from other sessions, though not listed.
Other options from the advisory: leave the experimental tasks feature disabled, or register your own task handlers that check session ownership before acting.
How to tell if you were hit
The advisory lists no indicators. In server logs, look for tasks/list calls followed by tasks/get, tasks/result or tasks/cancel on task IDs a session did not create. Tasks cancelled that the owning client did not cancel, and clients that report missing elicitation prompts, are signs of interference. Review which sessions call tasks/list at all, since most clients only query tasks they started.
Original advisory
From the GitHub Advisory Database (CC BY 4.0).
Summary
In affected versions, the default request handlers installed by the experimental tasks feature (server.experimental.enable_tasks()) did not check which session created a task before acting on it. On a server with more than one connected client, any client could observe, read results from, and cancel tasks belonging to other clients.
Am I affected?
Only if the developer's application server calls server.experimental.enable_tasks(). If grep -r enable_tasks over their codebase finds nothing, the application is not affected.
Details
When tasks support is enabled on the low-level server, default handlers are registered for tasks/list, tasks/get, tasks/result, and tasks/cancel. These handlers operated on the task identifier alone and kept no record of the session that created each task. Because tasks/list returned every task in the store, a connected client did not need to know any identifiers in advance: it could enumerate all tasks, read any task's status and result via tasks/get and tasks/result, retrieve queued task messages — such as elicitation requests intended for the task's creator, which are removed from the queue on delivery, so the intended recipient never receives them — and cancel any task via tasks/cancel.
Impact
Servers that call server.experimental.enable_tasks() and serve multiple clients are affected: one client can read other clients' task results and elicitation payloads, consume messages meant for them, and cancel their tasks. The feature is experimental and opt-in, so servers that never enable it are unaffected. Servers that registered their own task handlers instead of the defaults are affected only if those handlers have the same omission.
Mitigation
Upgrade to version 1.27.2 or later, in which task IDs generated by run_task() embed an opaque per-session marker and the default handlers restrict each session to its own tasks: requests for another session's task receive "task not found", and tasks/list returns only the requesting session's tasks. Tasks created with explicitly chosen IDs or written directly through a TaskStore remain reachable by ID but are not listed. Alternatively, leave the experimental tasks feature disabled, or register task handlers that validate session ownership.
Credited to cjmielke, dewankpant, shrutilohani.
Questions
- How do I know if my MCP server uses the tasks feature?
Run
grep -r enable_tasksover your code. The default handlers are only installed whenserver.experimental.enable_tasks()is called. No match means no exposure to this flaw.- Does the fix hide tasks with custom IDs?
Not fully. Tasks created with explicitly chosen IDs or written directly through a
TaskStorestay reachable by ID from other sessions in 1.27.2. They are not listed.- Is this the same as CVE-2026-52869?
No. CVE-2026-52869 is about HTTP transports routing requests to a session by ID alone. This one is about the experimental task handlers lacking an ownership check. Both are fixed in 1.27.2.
References
Read for this analysis:
- https://nvd.nist.gov/vuln/detail/CVE-2026-52870
- https://github.com/modelcontextprotocol/python-sdk/pull/2720
- https://github.com/modelcontextprotocol/python-sdk/commit/62137874ff26dd74d2fea80ff528a7fd9ca7a5e7
- https://github.com/modelcontextprotocol/python-sdk/releases/tag/v1.27.2
- https://github.com/advisories/GHSA-hvrp-rf83-w775
How this page is made: the data panel comes from the GitHub Advisory Database, CISA’s KEV catalog, the NVD and FIRST EPSS, and updates twice a day. The analysis is written by an AI model from the sources listed above and checked by automated rules before it is published. Check versions against the vendor's advisory before you act. Methodology
More MCP Python SDK vulnerabilities
All MCP Python SDK entriesCVE-2026-59951
MCP Python SDK: Unbounded Session Accumulation in StreamableHTTP Transport Enables Resource Exhaustion
medium7.5Oct 15, 2026CVE-2026-52869
MCP Python SDK: HTTP transports serve session requests without verifying the authenticated principal
high7.1Jul 16, 2026CVE-2026-59950
MCP Python SDK: WebSocket server transport does not support Host/Origin validation
high7.6Jul 16, 2026CVE-2025-66416
Model Context Protocol (MCP) Python SDK does not enable DNS rebinding protection by default
high7.6Dec 2, 2025CVE-2025-53365
MCP Python SDK has Unhandled Exception in Streamable HTTP Transport, Leading to Denial of Service
high8.7Jul 4, 2025CVE-2025-53366
MCP Python SDK vulnerability in the FastMCP Server causes validation error, leading to DoS
high8.7Jul 4, 2025
