MCP TypeScript SDK is the official TypeScript SDK for Model Context Protocol servers and clients. From version 1.24.0 to before version 1.32.0, the experimental tasks feature (taskStore) did not check which session created a task. Clients sharing one InMemoryTaskStore could list, read and cancel each other's tasks. This issue has been patched in version 1.32.0.
CVE-2026-109527 is a high-severity vulnerability in the Model Context Protocol Python SDK affecting versions before 1.29.1 and from 2.0.0a1 up to but not including 2.1.0. The issue involves the Streamable HTTP session manager, SSE message endpoint, and OAuth authorization-server routes buffering entire HTTP request bodies without enforcing size limits. This allows an unauthenticated remote attacker to send large request bodies that exhaust server memory, potentially causing denial of service. Servers using stdio-only or with upstream request size limits are not affected. The vulnerability is fixed in versions 1.29.1 and 2.1.0.
CVE-2026-108395 is a high-severity vulnerability in the Model Context Protocol Java SDK affecting multiple versions of the io.modelcontextprotocol.sdk:mcp artifact and mcp-core. The issue arises because certain server transports read HTTP request bodies into memory without enforcing a maximum size limit. This allows an unauthenticated remote attacker to send arbitrarily large POST requests, potentially exhausting the Java process heap and causing denial of service. The vulnerability affects versions from 0.8.0 up to but not including 0.13.0, from 0.13.0 up to 0.18.4, from 1.0.0 up to 1.1.4, and from 2.0.0-M1 up to 2.0.1. Fixed versions are 0.18.4, 1.1.4, and 2.0.1. Mitigations include authentication, origin or host validation, or upstream request size limits to reject malicious requests before they reach the vulnerable code.
CVE-2026-59951 is a medium severity vulnerability in the modelcontextprotocol python-sdk affecting versions 1.8.0 through 1.29.1 and 2.0.0 through 2.1.1. The issue involves uncontrolled resource consumption due to a Streamable HTTP server in stateful mode that never reclaims session state, allowing unlimited sessions to accumulate and consume memory. This can lead to server memory growth without bound until a restart occurs. The vulnerability is fixed in versions 1.30.0 and 2.2.0, which introduce session idle timeouts, maximum session limits, and proper session cleanup.
CVE-2026-108714 is a high-severity vulnerability in the modelcontextprotocol kotlin-sdk up to version 0.15.0. It involves uncontrolled memory allocation due to the lack of a maxFrameSize limit in the WebSocket implementation. This allows remote attackers to send frames with payloads near 2 GiB, causing excessive heap allocations and denial of service.
### Summary
In affected versions, the SDK's OAuth client let the MCP server decide which authorization server received the client's OAuth credentials. Credentials were not tied to the authorization server they belong to.
A malicious or compromised MCP server could name its own authorization server. With no user interaction, the client would send it:
- the `refresh_token` and `client_secret` stored from an earlier sign-in
- the `client_secret` or signed assertion configured on a bundled provider
### Am I affected?
Yes, if both of these hold:
- your application uses the SDK's OAuth client over HTTP, through any of:
- an `authProvider` on a transport
- the `withOAuth()` middleware
- direct calls to `auth()` or `fetchToken()`
- it may connect to an MCP server you do not fully trust while holding credentials for a legitimate authorization server
Affected versions:
- `@modelcontextprotocol/sdk` 1.12.0 through 1.30.1
- `@modelcontextprotocol/client` 2.0.0 through 2.1.0, only for:
- bundled providers without `expectedIssuer`
- credentials stored or supplied without `issuer`
- direct calls to `fetchToken()`
- providers that read storage back through `OAuthTokensSchema` or `OAuthClientInformationSchema`
Not affected:
- MCP servers built with the SDK
- stdio clients
### Fix
Upgrade to:
- 1.x: `@modelcontextprotocol/sdk` 1.31.0 or later
- 2.x: `@modelcontextprotocol/client` 2.2.0 or later, and `@modelcontextprotocol/core` 2.2.0 or later if you import it directly
The client now records the authorization server as `issuer` on saved credentials and does not send them to a different one. The user signs in again, or the call throws.
In the following cases, upgrading to the patched version is not enough. You also need to make a change:
- **Bundled providers** (`ClientCredentialsProvider`, `PrivateKeyJwtProvider`, `StaticPrivateKeyJwtProvider`, `CrossAppAccessProvider`): pass `expectedIssuer`, for example `expectedIssuer: 'https://auth.example.com'`. Without it they still use whichever authorization server the MCP server names.
- **Credentials saved without `issuer`:** tokens and client information your `OAuthClientProvider` persisted (file, keychain, database) before upgrading, including everything 1.x saved before 1.31.0. They still go to whichever authorization server is named at first use. Add `issuer` to them, or clear them so users sign in again.
- **Your own `OAuthClientProvider`:** save exactly what `saveTokens()` and `saveClientInformation()` are given, including `issuer`. For pre-registered credentials, include `issuer` in what `clientInformation()` returns.
Not covered by this fix:
- a new interactive sign-in, which still goes to the authorization server the MCP server names. Only complete sign-ins for servers you trust.
- `refreshAuthorization()` and `exchangeAuthorization()` called directly
- 2.x with `skipIssuerMetadataValidation: true`
If an affected client may have connected to an untrusted MCP server, rotate its client secret or signing key and revoke its tokens.
If you cannot upgrade yet, connect OAuth clients only to MCP servers you trust. 2.0.0 and 2.1.0 already accept `expectedIssuer`.
RMCP is an official Rust SDK for the Model Context Protocol. Prior to 2.1.0, the rmcp crate's StreamableHttpClientTransport in crates/rmcp/src/transport/common/reqwest/streamable_http_client.rs builds its default_http_client with reqwest's automatic redirect policy and applies caller-supplied values from StreamableHttpClientTransportConfig.custom_headers without marking them as sensitive. When a malicious or compromised MCP endpoint returns a cross-origin 307 or 308 redirect, reqwest follows the redirect and apply_custom_headers causes custom API keys or authentication tokens to be replayed to the new origin, where an attacker can capture and reuse them. The separate auth_header path is not affected because it uses the standard Authorization header, which reqwest strips on cross-origin redirects. This issue is fixed in version 2.1.0.
RMCP is an official Rust SDK for the Model Context Protocol. Prior to 2.0.0, the rmcp crate's OAuth implementation in crates/rmcp/src/transport/auth.rs omits the RFC 9728 resource field from ResourceServerMetadata and allows discover_oauth_server_via_resource_metadata to use protected-resource metadata without confirming that the returned resource identifier exactly matches the configured MCP server. A malicious MCP server can publish metadata for a different legitimate MCP resource and its authorization server, causing a victim who connects and completes the authorization flow to obtain a legitimate access token that the client subsequently sends to the malicious server. The attacker can capture the token and impersonate the victim against the legitimate MCP resource within the token's granted scopes. This issue is fixed in version 2.0.0.
RMCP is an official Rust SDK for the Model Context Protocol. Prior to 2.0.0, the rmcp crate's stateful Streamable HTTP server in crates/rmcp/src/transport/streamable_http_server/tower.rs allows an unauthenticated client to send a well-formed JSON-RPC POST that is not an initialization request, or an initialization request with a mismatched protocol header, causing StreamableHttpService::handle_post to call LocalSessionManager.create_session before validating the message. An early validation failure returns without removing the inserted LocalSessionHandle from LocalSessionManager.sessions, permanently retaining session and channel state for the server process lifetime. Repeated requests can grow the shared session table without bound, degrade legitimate-client latency through lock contention, exhaust memory, and terminate the server. This issue is fixed in version 2.0.0.
MCP Kotlin SDK is the Kotlin Multiplatform software development kit for the Model Context Protocol. In versions 0.7.0 through 0.12.0, `ReadBuffer.append` in `kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/ReadBuffer.kt` writes every chunk of bytes received from the stdio transport into a `kotlinx.io.Buffer` with no size cap. Frames are extracted from that buffer only when a `\n` (0x0a) byte is observed. A peer that streams bytes without ever sending a newline causes the internal buffer to grow indefinitely until the JVM (or the surrounding host process) is OOM-killed. The leak is amplified by `StdioServerTransport` and `StdioClientTransport`, which both queue raw chunks through a `kotlinx.coroutines.channels.Channel<ByteArray>(Channel.UNLIMITED)` and then call `readBuffer.append(chunk)` without backpressure or size guard. This is a remote-pre-auth denial of service whenever an SDK stdio server's stdin is fed by an untrusted or attacker-controlled producer (for example: a host program that exec's the MCP server as a subprocess and pipes through bytes received from a network peer, or a sidecar wrapper that proxies bytes from an HTTP endpoint to the stdio transport). Version 0.13.0 fixes the issue.
CVE-2026-53965 is a medium severity vulnerability in the Model Context Protocol PHP SDK (mcp/sdk) versions 0.5.0 through 0.7.0. The HTTP client transport reads Server-Sent Events (SSE) streams into an unbounded in-memory buffer, which only flushes upon receiving a double newline delimiter. A malicious or compromised server that never sends this delimiter can cause the buffer to grow indefinitely, exhausting client memory and causing a denial of service. This affects any client using HttpTransport against an untrusted server and requires no authentication or user interaction beyond connection initiation. The issue is fixed in version 0.7.1.
MCP Ruby SDK is the official Ruby SDK for Model Context Protocol servers and clients. Prior to 0.23.0, MCP::Server::Transports::StreamableHTTPTransport in the mcp gem reads and parses an entire JSON-RPC POST body without a size limit, allowing an unauthenticated remote attacker to exhaust process memory. This issue is fixed in version 0.23.0.
CVE-2026-67431 is a high-severity vulnerability in the MCP Ruby SDK prior to version 0.23.0. The issue involves improper access control where the StreamableHTTPTransport component does not bind session IDs to session owners. This flaw allows an attacker who has obtained a stolen session ID to send requests that execute within the victim's session context. The vulnerability is fixed in version 0.23.0.
MCP Ruby SDK is the official Ruby SDK for Model Context Protocol servers and clients. Prior to 0.23.0, MCP::Server::Transports::StdioTransport and MCP::Client::Stdio in the mcp gem use IO#gets without a byte limit, allowing a peer that sends data without a newline to exhaust process memory. This issue is fixed in version 0.23.0.
CVE-2026-67430 is a medium severity vulnerability in the MCP Ruby SDK prior to version 0.23.0. The issue involves the MCP::Server::Transports::StreamableHTTPTransport component not expiring sessions by default, causing unbounded retention of ServerSession objects. This can lead to memory exhaustion in the process due to repeated initialize requests. The vulnerability is fixed in version 0.23.0.
MCP Ruby SDK is the official Ruby SDK for Model Context Protocol servers and clients. Prior to 0.23.0, MCP::Server::Transports::StreamableHTTPTransport in the mcp gem does not validate the HTTP Host or Origin request headers, which allows a malicious browser page to use DNS rebinding to reach a locally running MCP server and invoke exposed tools. This issue is fixed in version 0.23.0.
### Summary
In affected versions, the deprecated WebSocket server transport (`mcp.server.websocket.websocket_server`) accepted the WebSocket handshake without applying any `Host` or `Origin` header validation. The `TransportSecuritySettings` mechanism that the SSE and Streamable HTTP transports use for this purpose was not wired into the WebSocket transport, so there was no SDK-level way to restrict which origins could connect.
### Am I affected?
Only if a developer's application server exposes `mcp.server.websocket.websocket_server`. This transport has never been part of the MCP specification, is marked deprecated, and is not reachable through `FastMCP` — a developer must have wired it into an ASGI application themselves. Servers using stdio, SSE, or Streamable HTTP are not affected by this advisory.
### Details
`websocket_server()` constructed a Starlette `WebSocket` and called `accept(subprotocol="mcp")` immediately, with no inspection of the connection's headers. By contrast, `SseServerTransport` and `StreamableHTTPServerTransport` accept an optional `security_settings: TransportSecuritySettings` and run `TransportSecurityMiddleware.validate_request()` against the incoming `Host` and `Origin` headers before establishing a session. Because browsers attach an `Origin` header to cross-origin WebSocket upgrade requests but do not enforce a same-origin policy on the response, a web page served from any origin could open a WebSocket to a reachable MCP server on this transport, complete the `initialize` handshake, and issue JSON-RPC requests on the resulting session.
### Impact
A user who runs an MCP server on this transport bound to localhost or a LAN address, without a separate authentication or origin gate in front of it, and visits a malicious web page, can have that page enumerate and invoke the server's tools and read its resources. The consequences depend entirely on what the server exposes. The transport itself requires no token or prior session. Some browsers prompt before allowing a public page to open a connection to a local-network address, which adds a user-interaction step but is not a substitute for server-side validation.
### Mitigation
Upgrade to version 1.28.1 or later, in which `websocket_server()` accepts the same optional `security_settings: TransportSecuritySettings` argument as the other HTTP-based transports and validates the `Host` and `Origin` headers before accepting the handshake; a request that fails validation is rejected with HTTP 403 and `ValueError("Request validation failed")` is raised to the caller. As with the other transports the parameter defaults to `None`, which leaves validation disabled, so upgrading alone does not change behaviour: pass a `TransportSecuritySettings` with `enable_dns_rebinding_protection=True` and appropriate `allowed_hosts` / `allowed_origins` to receive the protection. The recommended path remains to migrate off this deprecated transport to Streamable HTTP, where `FastMCP` enables this protection automatically for localhost binds. The WebSocket transport has been removed entirely in v2.
### 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.
### Summary
In affected versions, the SSE and Streamable HTTP server transports routed incoming requests to an existing session based only on the session identifier, without verifying that the request was authenticated as the same principal that created the session. Anyone who learned or guessed a session ID could send JSON-RPC messages on that session, regardless of which bearer token the request carried.
### Am I affected?
Only if a developer's application server uses an HTTP transport (SSE, or Streamable HTTP in stateful mode) **and** authenticates requests. Servers on stdio, stateless Streamable HTTP, or with no authentication configured are not affected.
### Details
Both transports look up the target session by its identifier alone — the `session_id` query parameter for SSE (`mcp.server.sse.SseServerTransport`) and the `Mcp-Session-Id` header for Streamable HTTP (`mcp.server.streamable_http_manager.StreamableHTTPSessionManager`). Once the lookup succeeded, the request was handled on that session without comparing its authentication context to the credentials presented when the session was created, so a request authenticated as a different OAuth client could inject messages into the session. On the SSE transport the response is delivered to the original client's event stream; on the Streamable HTTP transport it is returned on the injecting request, so the injecting client can also read the result. The SSE transport has been affected since the first release; the Streamable HTTP transport since version 1.8.0.
### Impact
Servers using either HTTP transport together with the SDK's built-in bearer-token authentication are affected: the per-client isolation that authentication provides can be bypassed for any session whose ID is known. Session IDs are randomly generated UUIDs, so exploitation requires obtaining one out of band (logs, network observation). Servers that do not enable bearer-token authentication have no per-client isolation to bypass and are not addressed by this advisory, and stateless Streamable HTTP deployments do not maintain sessions and are unaffected.
### Mitigation
Upgrade to version 1.27.2 or later, which records the authenticated principal that created each session — the OAuth client ID together with the token's issuer and subject when the token verifier supplies them — and answers requests presenting a different principal with the same 404 response as for an unknown session.
Deployments where many end users share a single OAuth client (hosted MCP clients, gateways) should ensure their token verifier populates `AccessToken.subject` (e.g. from the token's `sub` claim) so sessions are isolated per user rather than per client. Deployments using a custom authentication backend other than the built-in `BearerAuthBackend` should enforce an equivalent check themselves.
CVE-2026-44428 is a Server-Side Request Forgery (SSRF) vulnerability in the modelcontextprotocol (MCP) registry versions prior to 1.7.6. The issue arises because the GitHub OIDC token audience is globally fixed rather than bound to a specific registry instance, allowing tokens obtained from one MCP registry deployment to be accepted by others sharing the same code and audience string. This could lead to unauthorized actions based on repository ownership permissions. The vulnerability has a low severity score and is fixed in version 1.7.6.