Medium

MCP Streamable-HTTP Session Churn (Uncaught ClosedResourceError DoS)

This detects a pattern where a client keeps reconnecting to an MCP streamable-HTTP server, but each new connection carries almost no actual traffic before dying. That pattern matches how CVE-2025-53365 is exploited: a crafted request crashes the server's session handler, forcing constant restarts.

How the attack works

An attacker connects to an MCP server's streamable-HTTP endpoint and sends a request that triggers an unhandled ClosedResourceError in the MCP Python SDK (versions before 1.10.0). The server session crashes, so the client's connection is torn down almost immediately after it starts. The client reconnects to keep working, the new session gets killed the same way, and this repeats: many session re-establishments, each carrying at most a couple of requests. The rule watches for exactly this shape - reconnection rate rising while request volume per session stays flat and low.

Netzilo detection

Netzilo reports this behaviour when it is observed.

Signature ID
7f3c9d21-4b8e-4a6f-9c1d-5e2a8b4f6031
Severity
Medium

Why it matters

A single client can repeatedly crash the MCP server's session handling, denying service to that endpoint until someone restarts or patches it. The rule flags the pattern for investigation; it cannot confirm the crash itself or distinguish malicious triggering from ordinary instability.

What you can do

  • Upgrade the MCP Python SDK to 1.10.0 or later, which fixes CVE-2025-53365.
  • When this pattern appears, check server logs for ClosedResourceError or other unhandled exceptions around the time of each session drop.
  • Rule out benign causes first: hot-reload dev servers, container restarts/OOM kills, and proxies or load balancers with short idle timeouts all produce the same reconnect pattern.
  • Add process-crash and exception monitoring on the MCP server so future incidents can be confirmed directly instead of inferred from connection behavior.

Known benign look-alikes

  • Local MCP server run with hot reload (uvicorn --reload, nodemon, watchexec) restarting on every file save during development, forcing the client to re-establish the streamable HTTP session repeatedly.
  • Container or pod restart, rolling deploy, or crash-loop of the MCP server caused by an unrelated bug or an OOM kill.
  • Load balancer, service mesh sidecar, or reverse proxy with a short idle timeout terminating long-lived streamable HTTP sessions.
  • Flaky network, VPN or ZTNA tunnel re-key causing genuine TCP churn on an otherwise healthy session.
  • A batch or CI harness that intentionally runs many short one-shot MCP sessions in a loop against the same endpoint instead of reusing one session.
  • An HTTP client configured without keep-alive that polls an endpoint whose path happens to contain /mcp, /sse, /stream or /rpc.

References