Skip to content

Chainlit MCP: unauthenticated RCE and SSRF via /mcp when MCP is enabled (CVE-2026-45018 / CVE-2026-45019)

Summary

Chainlit published two GitHub Security Advisories on August 25, 2026 covering unauthenticated flaws in its MCP (Model Context Protocol) endpoint, both fixed in Chainlit 2.12.0 (released to PyPI 2026-08-25):

  • CVE-2026-45018 (GHSA-w3fx-mc44-mf6j, CVSS 9.8 Critical, CWE-78): command injection / remote code execution via the MCP stdio transport. The POST /mcp endpoint accepts a user-controlled fullCommand string; validate_mcp_command() checks only the executable name against config.features.mcp.stdio.allowed_executables and does not inspect arguments. npx -y -c 'PAYLOAD' passes the allowlist check while executing arbitrary shell commands with the privileges of the Chainlit process.
  • CVE-2026-45019 (GHSA-hvfh-5mj3-5f3j, CVSS 7.2 High, CWE-918): SSRF via the MCP sse and streamable-http transports. The request model defines url as a bare str with no scheme check, no private-IP filtering, and no allowlist, and (since 2.6.4) forwards attacker-controlled headers (e.g. Authorization, Cookie) to the target, enabling requests to internal services and cloud metadata endpoints.

Both require the operator to have set features.mcp.enabled = true in .chainlit/config.toml. MCP has been disabled by default since v2.7.0, so most deployments are not exposed. No authentication is required: /mcp is reachable by any client that can open a session. No exploitation, actor, or infrastructure detail is named in the advisories.

Tags

Vulnerability mechanics

  • Gate: both flaws live in the optional MCP feature. Impact requires features.mcp.enabled = true; the default since v2.7.0 is disabled.
  • CVE-2026-45018 (stdio): validate_mcp_command() in backend/chainlit/mcp.py parses the command with shlex.split() and allowlists only the executable name. Arguments are returned unchecked and passed to StdioServerParameters, which spawns the subprocess. Because npx supports -c for arbitrary shell execution, a command whose name is allowlisted (npx, uvx, …) still runs attacker-chosen commands: npx -y -c 'PAYLOAD'. Introduced when MCP support landed (PR #1977), affecting >=2.4.0rc0, <2.12.0.
  • CVE-2026-45019 (sse / streamable-http): the Pydantic request models in backend/chainlit/types.py accept url as an unvalidated string; the handler in backend/chainlit/server.py passes the URL and optional headers dictionary directly to the MCP SDK's sse_client() / streamablehttp_client(), which issue server-side outbound HTTP requests. The URL sink has existed since MCP support was introduced (PR #1977, >=2.4.0rc0); attacker-controlled header forwarding that amplifies it (credential/metadata exfil via spoofed Authorization/Cookie) was added in PR #2292 (>=2.6.4).
  • Fix: 2.12.0 (commit 0565fd0eccb915fce159929598b053ed79f6e0c9, release 2026-08-25); see also Chainlit's security advisory doc (docs/security-advisory-2026-mcp.md, SPL-2026-002 for the SSRF).

Defender heuristics

  1. Check the config, not just the version: on every exposed or internal Chainlit host, verify whether features.mcp.enabled is set. If MCP is not enabled, these flaws are not reachable; if it is enabled, treat the host as compromised-adjacent until 2.12.0.
  2. Upgrade to 2.12.0 on any deployment with MCP enabled; 2.12.0 shipped to PyPI on 2026-08-25 (advisory published the same evening, 2026-08-25 ~19:19/19:21 UTC).
  3. Hunt for post-exploitation artifacts on hosts that ran >=2.4.0rc0 with MCP enabled: unexpected npx -c / uvx child processes of the Chainlit service, new accounts/services, outbound requests from the Chainlit process to internal or 169.254.169.254/metadata endpoints with anomalous headers.
  4. Network-control the surface: restrict who can open a session to /mcp; egress-filter server-side outbound requests from the Chainlit process where possible. The RCE path is a textbook MCP stdio command-execution boundary failure — the same pattern as marimo's notebook-metadata MCP command injection (see related pages).
  5. Inventory AI-tooling MCP servers generally: this is part of a recurring class of MCP trust-boundary flaws (Meta Ads MCP unauthenticated tool execution, Grafana MCP readable-SSRF, Flyto2 Core callback secret disclosure) where MCP transports turn a reachable app into an unauthenticated proxy/executor.

Sources