Aug 25, 2026·6 min read·19 visits
Unauthenticated attackers can abuse the Model Context Protocol (MCP) endpoint in Chainlit to execute arbitrary HTTP requests to internal networks and local interfaces.
An unauthenticated server-side request forgery (SSRF) vulnerability exists in Chainlit versions >= 2.4.0rc0 and < 2.12.0 when the Model Context Protocol (MCP) features are enabled. This vulnerability allows remote, unauthenticated attackers to force the backend application server to initiate arbitrary HTTP/HTTPS connections to internal subnets, localhost endpoints, or cloud metadata infrastructure.
The Model Context Protocol (MCP) feature in the Chainlit conversational AI framework allows developers to integrate external services, APIs, and tools directly into conversational agents. To support these integrations, the platform exposes backend endpoints that communicate with external MCP servers using various protocols, including Server-Sent Events (SSE) and HTTP streaming models. In affected versions of Chainlit, the endpoint designated for connecting new MCP servers, specifically POST /mcp, does not validate client-provided network targets before establishing communication.
Because this endpoint is accessible without authentication by default, it presents a substantial attack surface. When a user requests a connection, the server attempts to parse and resolve the target URL provided in the request payload. In configurations where features.mcp.enabled = true is defined in the configuration, an attacker can submit requests targeting local network interfaces, enabling unauthorized interactions with internal systems.
This vulnerability is classified as a Server-Side Request Forgery (SSRF) and is tracked as CWE-918. Because the server accepts arbitrary destinations without strict validation, it functions as an open proxy to private network sectors that are typically isolated from external internet traffic.
The primary cause of the vulnerability is the absolute trust placed in the url and headers values provided within the client JSON body during calls to the /mcp endpoint. The platform uses specific Pydantic data models—such as ConnectSseMCPRequest and ConnectStreamableHttpMCPRequest—to validate schema conformance, but these models failed to perform any network-level validation or restriction on the target address.
When a connection payload is received, the backend controller directly extracts the url parameter and passes it to the asynchronous HTTP clients responsible for SSE and streaming HTTP transport mechanisms. There were no access control checks or IP address verification routines implemented to restrict connection attempts to localhost (such as 127.0.0.1 or [::1]), internal private networks defined by RFC 1918 (such as 10.0.0.0/8 or 192.168.0.0/16), or cloud environment metadata endpoints (such as 169.254.169.254).
Additionally, the HTTP client inside the underlying MCP SDK was configured to follow HTTP redirects automatically (follow_redirects=True). This behavior introduces an evasion technique where a target URL pointing to a benign external server responds with an HTTP 3xx redirect directive pointing to a local or internal network address, bypassing trivial string-matching or simple hostname resolution filters if they were present.
Before the fix was implemented in version 2.12.0, the models in backend/chainlit/types.py parsed incoming payloads directly without validating the destination host:
# Vulnerable implementation in backend/chainlit/types.py
class ConnectSseMCPRequest(BaseModel):
sessionId: str
clientType: Literal["sse"]
name: str
url: str # Target URL was taken as an unvalidated raw string
headers: Optional[Dict[str, str]] = NoneThe server processed this model directly within the connect_mcp routine in backend/chainlit/server.py:
# Vulnerable implementation in backend/chainlit/server.py
if isinstance(mcp_connection, SseMcpConnection):
transport = await exit_stack.enter_async_context(
sse_client(
url=mcp_connection.url, # Unvalidated injection into HTTP client
headers=mcp_connection.headers,
)
)The patch implemented in commit 0565fd0eccb915fce159929598b053ed79f6e0c9 introduces structured sanitization. The updated workflow requires user-provided connections to match explicit white-lists, and uses a custom validation module to analyze URL characteristics before dispatching requests:
def _has_ambiguous_path(raw_path: str) -> bool:
lowered = raw_path.lower()
# Blocks double-encoding and path-traversal bypass patterns
if any(marker in lowered for marker in ("%2e", "%2f", "%5c", "%25")):
return True
if "\\" in raw_path:
return True
if any(segment in (".", "..") for segment in raw_path.split("/")):
return True
if not raw_path.isascii():
return True
try:
decoded = unquote(raw_path, errors="strict")
except UnicodeDecodeError:
return True
return not decoded.isascii()This is reinforced by constructing a custom HTTP client factory using httpx.AsyncClient that hooks into the request workflow. It enforces follow_redirects=False and registers a request-checking hook _check_request to validate the resolved IP address of every outgoing destination on the wire immediately before connection, neutralizing DNS rebinding attacks.
Exploiting this vulnerability requires the target deployment to have MCP enabled. An unauthenticated attacker sends a structured POST request to the /mcp route containing the target host. Because the application server resides inside the internal perimeter, it attempts to establish the connection directly.
To conduct internal host or port scanning, an attacker can supply targets systematically. If the target service is online and accepts the request, the application responds with a connection error or diagnostic message indicative of a protocol mismatch. If the target port is closed or filtered, the server returns a connection timeout or connection refused error after a noticeable delay.
Additionally, attackers can manipulate the headers argument within the payload. Because these headers were previously forwarded without filtering, attackers could inject credentials, Authorization tokens, or session cookies to target private admin panels or internal databases that rely on reverse-proxy authorization headers for security.
The impact of CVE-2026-45019 is classified as High, receiving a CVSS 3.1 base score of 7.2. The security scope is modified (S:C) because the vulnerable server acts as a proxy, leveraging its trusted internal positioning to perform actions on other machines within the hosting infrastructure.
In containerized environments and cloud-managed infrastructure, this SSRF permits access to local daemon services, such as Docker sockets, Kubernetes API endpoints, or database administrations panels (e.g., Redis, Elasticsearch, database instances) that do not enforce strict access control controls for internal connections.
When deployed on public cloud engines (such as AWS, GCP, or Azure), the attacker can query the cloud metadata service at 169.254.169.254. This can lead to the exposure of temporary IAM role credentials, resulting in access to cloud storage buckets, databases, and configuration settings.
The primary resolution is upgrading the Chainlit framework installation to version 2.12.0 or higher, where the security boundaries and validation factory are implemented.
If upgrading is not immediately possible, you should disable the MCP functionality manually. Open the configuration file located at .chainlit/config.toml and verify that the feature flag is disabled:
[features.mcp]
enabled = falseAdditionally, implement strict firewall configuration (such as iptables or cloud security groups) for the application server hosting Chainlit. Block any outbound requests originating from the application user or process that target the local address space (127.0.0.0/8, 169.254.169.254, and private subnets) unless explicitly required by the system architecture.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Chainlit Chainlit | >= 2.4.0rc0, < 2.12.0 | 2.12.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-918 |
| Attack Vector | Network |
| CVSS | 7.2 |
| EPSS | Not Available |
| Impact | Server-Side Request Forgery (SSRF) |
| Exploit Status | PoC |
| KEV Status | Not Listed |
The web server receives a URL or similar vector from an upstream source and retrieves the contents of this URL, but does not sufficiently protect the resource request.
CVE-2026-109619 (PHP2Shell) is a critical Use-After-Free vulnerability in the core PHP engine caused by improper global state cleanup during out-of-memory exception handling across persistent worker requests.
In Python virtualenv prior to version 21.14.9, activation script generators and configuration writers use Path.exists() before writing files. Because Path.exists() resolves symbolic links, it returns False for dangling symlinks. Consequently, virtualenv skips unlinking pre-planted symbolic links or hard links, writing data directly to target locations outside the intended virtual environment directory.
A remote code execution vulnerability exists in Microsoft .NET due to untrusted data deserialization within the PresentationCore component. The flaw stems from implicit auto-conversion flags during clipboard data retrieval operations.
An out-of-bounds write vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio allows unauthenticated remote attackers to execute arbitrary code via crafted pixel-shader bytecode or auto-converted clipboard payloads.
ASP.NET Core contains a thread deadlock vulnerability (CWE-833) that allows an unauthenticated remote attacker to cause a denial of service over the network by exhausting server thread pool resources.
CVE-2026-70035 is a high-severity Remote Code Execution (RCE) vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio caused by improper handling during the deserialization of untrusted data (CWE-502). An unauthenticated attacker can execute arbitrary code within the context of the affected process by delivering a crafted serialized payload.