Jul 16, 2026·7 min read·4 visits
The MCP Python SDK failed to bind active session identifiers to authenticated client principals, allowing any bearer-token-authenticated user to hijack and inject JSON-RPC messages into another client's session by supplying their session ID.
An authorization bypass vulnerability exists in the Model Context Protocol (MCP) Python SDK prior to version 1.27.2. The Server-Sent Events (SSE) and stateful Streamable HTTP transports route incoming JSON-RPC requests based purely on user-controlled session identifiers without validating ownership, enabling authenticated attackers to inject commands into other sessions.
The Model Context Protocol (MCP) Python SDK provides a standardized framework for exposing local tools, resources, and prompts to Large Language Models over stateful communication channels. Among its core transport options are Server-Sent Events (SSE) and stateful Streamable HTTP, both implemented to enable long-lived, bi-directional messaging between clients and servers. These transport components process JSON-RPC request payloads, mapping asynchronous HTTP calls back to their corresponding active runtime sessions.
In multi-tenant environments or deployments utilizing token-based access control, the MCP server relies on authentication middleware to validate client identities prior to session interaction. The underlying transport layer is responsible for preserving session isolation, ensuring that clients can only read from or write to their own active communication streams. This isolation forms a critical boundary, especially when MCP servers expose powerful execution-level capabilities like system tool invocation.
Prior to the release of version 1.27.2, a severe authorization bypass flaw existed within the session management implementation of the SseServerTransport and StreamableHTTPSessionManager classes. The transport layers routed incoming JSON-RPC write requests solely on user-controlled session identifiers without verifying if the requesting client owned the target session. Consequently, any bearer-token-authenticated user could bypass access boundaries and hijack active sessions belonging to other authenticated principals.
The root cause of CVE-2026-52869 is an instance of CWE-639: Authorization Bypass Through User-Controlled Key. When a client establishes a stateful connection via the Server-Sent Events (SSE) endpoint (GET /sse), the MCP server allocates a high-entropy, randomly generated UUID to represent the session ID. The client then sends subsequent stateful JSON-RPC commands as HTTP POST requests targeting the message endpoint (POST /messages/?session_id=<UUID>).
While the server's authentication layer successfully validated incoming bearer tokens (via the BearerAuthBackend), it did not associate the authenticated principal with the generated session identifier. The routing engine assumed that possession of a valid session ID was sufficient authorization to interact with that session. This architectural assumption created a critical vulnerability when multiple distinct clients shared access to the same endpoint.
An attacker with valid, low-privilege credentials could present their own valid bearer token to satisfy the middleware's token validation check. By simultaneously appending a victim's active session ID in the query string or the Mcp-Session-Id header, the attacker bypassed session boundaries. The SDK transport layer accepted the HTTP POST request as authenticated and routed the JSON-RPC command directly into the target user's input execution stream.
The vulnerability was addressed across two primary commits in version 1.27.2. The first commit, 1abcca2, introduced the structural identity components by extending the AccessToken model to parse and store token claims, specifically mapping the token's subject (subject) and other authorization attributes. The second commit, ce267b6, implemented the actual transport-level ownership validation by introducing an AuthorizationContext mapping.
The SseServerTransport class was modified to track session owners in a secure internal dictionary (_session_owners: dict[UUID, AuthorizationContext]). When a client executes connect_sse, the server captures the validated user principal from the request scope and binds it to the newly generated session_id.
# Pre-patch logic in sse.py (Conceptual)
session_id = uuid4()
self._read_stream_writers[session_id] = read_stream_writer# Post-patch logic in sse.py
session_id = uuid4()
user = scope.get("user")
if isinstance(user, AuthenticatedUser):
self._session_owners[session_id] = authorization_context(user)
self._read_stream_writers[session_id] = read_stream_writerDuring subsequent message handling, the incoming request's authenticated user is parsed to extract their AuthorizationContext. The server then compares this context against the mapped owner of the target session. If the identities do not match, the server returns an HTTP 404 Not Found response. This defensive choice prevents session enumeration attacks by avoiding explicit "Unauthorized" indicators.
# Verification logic in handle_post_message
user = scope.get("user")
requestor = authorization_context(user) if isinstance(user, AuthenticatedUser) else None
if requestor != self._session_owners.get(session_id):
# If the credentials do not match, we respond with a 404
logger.warning("Rejecting message for session %s: credential does not match", session_id)
response = Response("Could not find session", status_code=404)
return await response(scope, receive, send)Exploitation of CVE-2026-52869 requires that the attacker has low-privilege access to the MCP server's network-facing endpoints and possesses a valid, authenticated credential. The attacker must also discover or accurately predict an active user's session_id. While the SDK uses UUIDv4 for session identifiers—making brute-force guessing computationally infeasible—session IDs may be leaked through insecure logging, network traffic analysis, or diagnostic outputs.
Once an active session ID is obtained, the attacker constructs a standard JSON-RPC payload targeting the victim's active session. This payload can instruct the server to run any supported tool or read local resources in the context of the victim's privileges. The attacker sends this payload as an HTTP POST request to the message endpoint, appending the victim's session ID while providing their own valid bearer token in the Authorization header.
The server receives the request, passes it through the authentication middleware successfully, and inspects the session_id. Under vulnerable versions, the routing engine forwards the JSON-RPC execution message into the victim's state queue. The target MCP server then processes and executes the action, treating it as if it originated from the victim's active connection. The output or error response is directed back to the victim's SSE read stream, potentially leaking information or executing arbitrary code via system-level tools.
The impact of this vulnerability depends on the specific tools and capabilities exposed by the target MCP server. Because MCP servers are frequently designed to grant large language models execution capabilities (such as database query execution, file system access, or command-line operations), hijacking an active session allows an attacker to execute administrative tasks under the victim's security context.
The vulnerability represents a complete bypass of multi-tenant boundaries. An attacker can transition from an isolated, low-privilege role to a high-privilege state by targeting sessions owned by administrators or service accounts. This represents a significant risk of data exposure, lateral movement, or unauthorized state mutation on systems managed via the Model Context Protocol.
The CVSS v3.1 score of 7.1 reflects this severe potential, balanced by the high attack complexity required to obtain the target session identifier. Because session IDs are high-entropy UUIDs, widespread opportunistic exploitation is unlikely. However, in targeted scenarios where session IDs are exposed via external vectors, exploitation is highly reliable and trivial to execute.
The primary remediation for CVE-2026-52869 is updating the mcp library to version 1.27.2 or higher. Organizations utilizing the python-sdk must verify their installed versions across all active deployments. This update modifies the core transport routing mechanisms to enforce the principal checks automatically.
For deployments utilizing custom authentication middleware rather than the built-in BearerAuthBackend, manual configuration is required. Developers must ensure that their custom backend correctly maps the authenticated user principal as an AuthenticatedUser containing an AccessToken with client_id, issuer, and subject populated. If these fields are omitted or partially implemented, the transport-layer validation may fall back to weak checks, leaving the system partially vulnerable.
Furthermore, security teams should implement auxiliary defenses to minimize session ID exposure. This includes enforcing Transport Layer Security (TLS 1.3) across all endpoints, stripping sensitive headers from intermediate proxy logs, and configuring short lifespans for active SSE sessions to reduce the exploitation window.
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
mcp (PyPI) Model Context Protocol | < 1.27.2 | 1.27.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-639 |
| Attack Vector | Network |
| CVSS Score | 7.1 (High) |
| Exploit Status | poc |
| Impact | Authorization Bypass, Hijacking |
| KEV Status | Not Listed |
The system utilizes user-controlled keys to look up and route requests to an existing session, without performing validation to ensure that the requestor possesses authorization to access that specific session resource.
An Improper Authorization Bypass (Insecure Direct Object Reference) exists in ArcadeDB server prior to version 26.7.2. Fourteen specific HTTP handlers fail to validate permissions before retrieving and operating on a database instance. This architectural gap allows authenticated users authorized for only one database to read from and write to any other database on the server without restriction.
CVE-2026-48939 is a critical vulnerability in the iCagenda events calendar extension for Joomla that allows unauthenticated remote attackers to execute arbitrary code via unrestricted file uploads. The flaw stems from a lack of server-side validation of file uploads and missing authorization checks at the controller level. Successful exploitation results in complete compromise of the affected web application host.
A Denial of Service (DoS) vulnerability in the Rust crate `serde_with` arises from an integer underflow and uncontrolled memory allocation during the processing of empty collections using the `KeyValueMap` helper. Depending on the build profile, this flaw leads to an immediate thread panic (debug) or process abort due to an out-of-memory condition (release).
A high-severity vulnerability exists in the adawolfa/isdoc PHP library before versions 1.4.1 and 2.0.0. The library fails to restrict or validate the sizes of files extracted from untrusted Zip archives (.isdocx container files) or PDF embedded streams. This allows remote attackers to perform decompression bomb attacks, causing denial of service via memory or disk exhaustion.
A critical remote code execution vulnerability exists in django-haystack prior to version 3.4.0. The vulnerability stems from the Elasticsearch 1.x search backend incorrectly processing aliased search result fields, leading to the unsafe execution of user-supplied strings using Python's built-in eval() function.
The obsidian-local-rest-api plugin prior to version 4.1.3 is vulnerable to an authenticated path traversal flaw in its /vault/{path} endpoints. An authenticated attacker can bypass the vault root boundary using URL-encoded directory traversal sequences to perform unauthorized operations on the host filesystem.