{"slug": "cve-2026-45018-chainlit-mcp-stdio-unauthenticated-rce-and-sibling-cve-2026-45019", "title": "CVE-2026-45018: Chainlit MCP stdio unauthenticated RCE (and sibling CVE-2026-45019)", "summary": "Chainlit 2.12.0 patches two critical vulnerabilities in its MCP endpoint: CVE-2026-45018, an unauthenticated remote code execution via the stdio transport, and CVE-2026-45019, an unauthenticated server-side request forgery via SSE and streamable-http. Both require the MCP feature to be enabled, which is off by default since version 2.7.0. The fixes remove client-supplied commands and enforce URL allowlists, but users with MCP enabled should upgrade immediately.", "body_md": "*Originally published at HOL*\n\nChainlit 2.12.0 (2026-08-25) closes two bugs on `/mcp`\n\n. CVE-2026-45018 is unauthenticated command execution via the MCP stdio transport. CVE-2026-45019 is unauthenticated SSRF via SSE and streamable-http. Both require `features.mcp.enabled = true`\n\n. MCP is off by default since 2.7.0. If that flag is false, you can stop here.\n\n`features.mcp.enabled`\n\nis missing or false in `.chainlit/config.toml`\n\n.This is not every MCP CVE in the ecosystem. It is not LiteLLM's authenticated MCP stdio test-endpoint issue.\n\nWith MCP on, `POST /mcp`\n\naccepted a client-supplied `fullCommand`\n\nwhen `clientType`\n\nwas `stdio`\n\n. `validate_mcp_command()`\n\nin `backend/chainlit/mcp.py`\n\nsplit the string and checked only the executable basename against `allowed_executables`\n\n(examples: `npx`\n\n, `uvx`\n\n). Arguments were not inspected. Common Node launchers can run an arbitrary shell string through a short flag, so an allowlisted basename plus client-controlled arguments still ran as the Chainlit user before the MCP handshake failed. SPL Security (Vipin and Stephen) reported working proofs against 2.11.0. Vendor severity for SPL-2026-001 / CVE-2026-45018 is CVSS 3.1 9.8. Affected range: `>=2.4.0rc0, <2.12.0`\n\nwith MCP enabled. GitHub advisory GHSA-w3fx-mc44-mf6j.\n\nCVE-2026-45019 (SPL-2026-002, CVSS 3.1 7.2, GHSA-hvfh-5mj3-5f3j) is the sibling. For `sse`\n\nand `streamable-http`\n\n, the same endpoint took a raw `url`\n\nand optional `headers`\n\nwith no scheme check, no host allowlist, and no header denylist. The process made outbound HTTP, including caller-controlled auth headers, toward internal hosts and link-local metadata endpoints. Blind SSRF: response bodies stay inside the MCP client. Header forwarding for that path arrived in 2.6.4.\n\nIf `allowed_executables`\n\nis removed so the value is `None`\n\n, validation allows every executable. The allowlist is not a safety net by itself.\n\nNot default-on. Not fixed by shrinking `allowed_executables`\n\n; 2.12.0 removes client-supplied commands. After upgrade, anonymous clients can still start developer-named stdio servers by name if auth is off. That is pinned-command start, not client-chosen RCE.\n\nRun `pip show chainlit`\n\nand print `chainlit.__version__`\n\nfrom the same environment that serves the app. Open `.chainlit/config.toml`\n\nand look for `features.mcp.enabled`\n\n, `allowed_executables`\n\n, `user_servers`\n\n, and `[[features.mcp.servers]]`\n\n. A Version below 2.12.0 with MCP enabled is exposed. Restart after upgrade so an old wheel is not still listening.\n\n```\npip install --upgrade 'chainlit==2.12.0'\n```\n\nThen restart Chainlit. 2.12.0 breaks old MCP config: `[features.mcp.sse]`\n\n, `[features.mcp.stdio]`\n\n, `[features.mcp.streamable-http]`\n\n, and `allowed_executables`\n\nabort startup when MCP is on. Declare stdio servers under `[[features.mcp.servers]]`\n\nand connect by name. User-provided SSE/HTTP needs `[features.mcp.user_servers] enabled = true`\n\nand a non-empty `allowed_urls`\n\n. Redirects are not followed; put the final HTTPS URL in config.\n\nIf you cannot upgrade today: set `features.mcp.enabled = false`\n\n, restrict egress, and register auth so `/mcp`\n\nis not anonymous. Auth alone does not remove command execution for an authenticated user on vulnerable builds; it only removes the anonymous path.\n\nGitHub advisory pages still showed empty patched versions at research time; the 2.12.0 release and in-tree MCP advisory name 2.12.0 as the fix.\n\nThis is the operator write-up. The [HOL Guard evidence page](https://hol.org/guard/security/cves/CVE-2026-45018?utm_source=devto&utm_medium=syndication&utm_campaign=blog_distribution&utm_content=cve-2026-45018-chainlit-mcp-stdio-unauth-rce-2) is the source record for CVE-2026-45018; sibling evidence for CVE-2026-45019 is at [HOL Guard CVE-2026-45019](https://hol.org/guard/security/cves/CVE-2026-45019?utm_source=devto&utm_medium=syndication&utm_campaign=blog_distribution&utm_content=cve-2026-45018-chainlit-mcp-stdio-unauth-rce-2).", "url": "https://wpnews.pro/news/cve-2026-45018-chainlit-mcp-stdio-unauthenticated-rce-and-sibling-cve-2026-45019", "canonical_source": "https://dev.to/hol/cve-2026-45018-chainlit-mcp-stdio-unauthenticated-rce-and-sibling-cve-2026-45019-30bp", "published_at": "2026-08-31 04:45:39+00:00", "updated_at": "2026-08-31 04:51:25.091254+00:00", "lang": "en", "topics": ["ai-safety", "ai-infrastructure", "developer-tools"], "entities": ["Chainlit", "CVE-2026-45018", "CVE-2026-45019", "SPL Security", "HOL Guard"], "alternates": {"html": "https://wpnews.pro/news/cve-2026-45018-chainlit-mcp-stdio-unauthenticated-rce-and-sibling-cve-2026-45019", "markdown": "https://wpnews.pro/news/cve-2026-45018-chainlit-mcp-stdio-unauthenticated-rce-and-sibling-cve-2026-45019.md", "text": "https://wpnews.pro/news/cve-2026-45018-chainlit-mcp-stdio-unauthenticated-rce-and-sibling-cve-2026-45019.txt", "jsonld": "https://wpnews.pro/news/cve-2026-45018-chainlit-mcp-stdio-unauthenticated-rce-and-sibling-cve-2026-45019.jsonld"}}