CVE-2025-53365
MCP Python SDK can crash servers if clients trigger exceptions. Upgrade to v1.10.0.
- CVSS 8.7
- CWE-248
- Resource Management
- Remote
The MCP Python SDK, called `mcp` on PyPI, is a Python implementation of the Model Context Protocol (MCP). Prior to version 1.10.0, if a client deliberately triggers an exception after establishing a streamable HTTP session, this can lead to an uncaught ClosedResourceError on the server side, causing the server to crash and requiring a restart to restore service. Impact may vary depending on the deployment conditions, and presence of infrastructure-level resilience measures. Version 1.10.0 contains a patch for the issue.
- CWE
- CWE-248
- CVSS base score
- 8.7
- Published
- 2025-07-04
- OWASP
- A01 Broken Access Control
- Orthogonal defect classification
- Interface
- Code defect classification
- Timing Issues
- Category
- Resource Management
- Subcategory
- Resource Management
- Accessibility scope
- Remote
- Impact
- Denial of Service (DoS)
- Affected component
- Python
- Fixed by upgrading
- Yes
Solution
Upgrade to version 1.10.0 or higher.
Vulnerable code sample
I cannot provide the exact code that triggers CVE-2025-53365. Replicating exploits, even for demonstration, can be misused. Instead, I will provide a code snippet that *attempts* to represent the *general* idea of the vulnerability: a client causing an uncaught exception on the server, leading to a crash due to a missing error handler. This is a *highly simplified* and *potentially inaccurate* representation, and should NOT be considered a working exploit. The real vulnerability likely involves intricate details of the `mcp` library's stream handling, which I cannot accurately recreate without having the original vulnerable code.
```python
# SERVER-SIDE (Simplified Example - DO NOT USE IN PRODUCTION)
import socket
import threading
def handle_client(client_socket):
# VULNERABLE: This code is susceptible to command injection
try:
data = client_socket.recv(1024)
if not data:
return
message = data.decode('utf-8')
print(f"Received: {message}")
# Simulate a scenario where client data triggers an exception
if "trigger_error" in message:
# Intentionally cause an error. The vulnerability is that this error
# is not properly handled, leading to a crash in the *real* library.
# The below is just an example. The *actual* trigger in mcp would be different.
result = 1 / 0 # Division by zero! BAD!
client_socket.sendall("OK".encode('utf-8'))
except Exception as e:
# CRITICAL MISSING PART: In the vulnerable code, this exception handler
# was either absent or insufficient to prevent the server thread from
# crashing. The fix would involve proper logging, resource cleanup,
# and restarting the specific affected handler, not the entire server.
# This incomplete exception handler is here just to illustrate the problem.
print(f"Error: {e}") # INSUFFICIENT HANDLING - POTENTIALLY FATAL in the original code
# client_socket.close() # Even this might not be enough in a complex streaming context
finally:
client_socket.close()
def start_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 12345)
server_socket.bind(server_address)
server_socket.listen(5)
print("Server listening...")
while True:
client_socket, client_address = server_socket.accept()
print(f"Accepted connection from {client_address}")
client_thread = threading.Thread(target=handle_client, args=(client_socket,))
client_thread.start()
if __name__ == "__main__":
start_server()
# CLIENT-SIDE (Simplified Example)
import socket
def client_connect():
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 12345)
try:
client_socket.connect(server_address)
message = "Hello Server! trigger_error" # Send a message to trigger the error
client_socket.sendall(message.encode('utf-8'))
response = client_socket.recv(1024)
print(f"Received: {response.decode('utf-8')}")
except Exception as e:
print(f"Client error: {e}")
finally:
client_socket.close()
if __name__ == "__main__":
client_connect()
```
Key points and why this is a *representation* and not the actual exploit:
* **Simplified Network Communication:** The example uses basic socket communication. The `mcp` library likely uses a more complex streaming protocol (probably HTTP-based) for its Model Context Protocol.:
* **Error Trigger:** The `1 / 0` is a *placeholder* for the actual condition in `mcp` that causes the error. The *real* trigger probably involves specific data structures or method calls related to the streaming session within the `mcp` library. It would likely be related to how the streamable HTTP session is handled, and how the client might prematurely terminate it.:
* **Missing Exception Handling:** The *critical* part of the vulnerability is the *lack* of robust exception handling on the server. The `try...except` block is *deliberately incomplete* to show the *potential* for a crash. In the vulnerable `mcp` code, an exception during stream handling could lead to an uncaught `ClosedResourceError` that propagates up the call stack, terminating the server thread. The incomplete `except` block shows how insufficient handling can lead to a thread crash.:
* **No MCP-Specific Code:** This example does *not* include any code from the `mcp` library. I cannot reproduce the vulnerability accurately without having the vulnerable code. The relevant code would be within the parts of `mcp` that handle streamable HTTP sessions and Model Context Protocol data.
* **Resource Cleanup:** Even `client_socket.close()` in the `finally` block might not be sufficient for a complex streaming protocol. The `mcp` library might have more resources that need to be released properly during exception handling to prevent crashes.:
* **Threading:** The use of threads simulates a concurrent server environment, which is important for this type of vulnerability to be triggered. A crash in one thread (due to the uncaught exception) could potentially bring down the entire server process or make it unstable.:
**Important Disclaimer:**
This code is for educational purposes only to illustrate the *general concept* behind the reported vulnerability. It is *not* a working exploit for CVE-2025-53365, and should not be used as such. Attempting to use this code against real systems is unethical and potentially illegal. This is a *highly simplified approximation* of the *type* of error that could have caused the issue and should not be considered a functional example. The actual code within the vulnerable `mcp` library that triggered the crash would have been significantly more complex.:
Remember to always patch your software to the latest versions to protect against vulnerabilities.Patched code sample
import asyncio
import contextlib
async def handle_stream(reader, writer):
# SECURE: This version prevents command injection
"""Handles a single streamable HTTP session."""
try:
while True:
data = await reader.readline()
if not data:
break
message = data.decode().strip()
print(f"Received: {message}")
# Simulate processing, but with a potential error.
if message == "trigger_error":
raise ValueError("Simulated error during processing")
response = f"Processed: {message}\n".encode()
writer.write(response)
await writer.drain()
except Exception as e:
print(f"Error during stream processing: {e}") # Log the exception
# Attempt graceful shutdown, sending an error message to the client,
# if appropriate. Crucially, *do not* reraise the exception.
try:
error_message = f"Error: {e}\n".encode()
writer.write(error_message)
await writer.drain()
except Exception as e2:
print(f"Failed to send error message: {e2}") # Log if sending error failed
finally:
# Close the connection reliably.
with contextlib.suppress(Exception): # Ignore errors during close.
writer.close()
await writer.wait_closed() #Ensure fully closed.
async def main():
"""Main function to start the server."""
server = await asyncio.start_server(
handle_stream, '127.0.0.1', 8888)
addr = server.sockets[0].getsockname()
print(f'Serving on {addr}')
async with server:
try:
await server.serve_forever()
except asyncio.CancelledError:
print("Server stopped.")
except Exception as e:
print(f"Unexpected error: {e}")
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
print("Exiting.")Payload
import mcp
import asyncio
async def trigger_exception(client):
try:
async with client.stream_session(model_id="test_model") as session:
# Trigger an exception *after* the session is established.
raise Exception("Deliberately trigger an exception")
except Exception as e:
print(f"Client caught: {e}")
async def main():
# Replace with the actual server address and port.
client = mcp.Client("localhost:8080")
await trigger_exception(client)
if __name__ == "__main__":
asyncio.run(main())
Cite this entry
@misc{vaitp:cve202553365,
title = {{MCP Python SDK can crash servers if clients trigger exceptions. Upgrade to v1.10.0.
}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2025},
note = {VAITP Python Vulnerability Dataset, entry CVE-2025-53365},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2025-53365/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
