Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-45018

CVE-2026-45018: Chainlit Python Framework RCE Vulnerability

CVE-2026-45018 is a remote code execution vulnerability in Chainlit that allows attackers to execute arbitrary shell commands through unauthenticated MCP endpoints. This post covers technical details, affected versions, and mitigation.

Published:

CVE-2026-45018 Overview

CVE-2026-45018 is a command injection vulnerability in Chainlit, a Python framework for building production-ready conversational AI applications. Affected versions from 2.4.0rc0 up to (but not including) 2.12.0 expose an unauthenticated POST /mcp endpoint when features.mcp.enabled is set to true in .chainlit/config.toml. An attacker can supply a crafted fullCommand string to execute arbitrary shell commands with the privileges of the Chainlit process. The flaw is tracked as [CWE-78] (OS Command Injection) and fixed in version 2.12.0.

Critical Impact

Unauthenticated remote attackers can achieve arbitrary command execution on any Chainlit deployment with the Model Context Protocol (MCP) feature enabled.

Affected Products

  • Chainlit 2.4.0rc0 through versions prior to 2.12.0
  • Deployments with features.mcp.enabled = true in .chainlit/config.toml
  • Configurations where config.features.mcp.stdio.allowed_executables is unset (defaults to None, permitting any executable)

Discovery Timeline

  • 2026-08-25 - CVE-2026-45018 published to the National Vulnerability Database (NVD)
  • 2026-08-25 - Last updated in the NVD database

Technical Details for CVE-2026-45018

Vulnerability Analysis

The vulnerability resides in Chainlit's MCP integration. When MCP is enabled, the POST /mcp endpoint is exposed without any authentication requirement. For the stdio transport, the request body accepts a user-controlled fullCommand string that Chainlit uses to launch a subprocess. The validate_mcp_command() function in backend/chainlit/mcp.py inspects only the executable name and matches it against config.features.mcp.stdio.allowed_executables. It then forwards the remaining, unvalidated arguments to StdioServerParameters in backend/chainlit/server.py.

Because tools such as npx accept a -c flag that runs an arbitrary shell string, an attacker who supplies npx -c "<command>" bypasses the executable allowlist entirely. This yields code execution as the Chainlit process user, which typically owns application secrets, model API keys, and access to internal services.

Root Cause

The root cause is incomplete input validation of the fullCommand argument combined with missing authentication on the MCP endpoint. Validation logic gates only the executable basename and never sanitizes subsequent arguments. Additionally, an unset allowed_executables value defaults to None, which the code interprets as "allow all," widening the attack surface for default deployments.

Attack Vector

Exploitation is remote and requires no authentication or user interaction. An attacker sends a single HTTP POST request to /mcp containing a stdio transport specification with a malicious fullCommand. Any executable that supports inline shell evaluation (for example npx -c, bash -c, python -c) can serve as the command injection primitive to reach arbitrary OS command execution.

python
# Patch excerpt from backend/chainlit/session.py (Chainlit 2.12.0)
# Source: https://github.com/Chainlit/chainlit/commit/0565fd0eccb915fce159929598b053ed79f6e0c9

_CLOSE_TIMEOUT = 10.0  # seconds to wait for a background MCP task to finish


async def stop_mcp_task(
    task: asyncio.Task, stop_event: asyncio.Event, name: str
) -> None:
    """Signal an MCP background task to shut down and wait for it."""
    stop_event.set()
    try:
        await asyncio.wait_for(task, timeout=_CLOSE_TIMEOUT)
    except asyncio.TimeoutError:
        logger.warning(
            "MCP session %r did not shut down within %.1fs — cancelling",
            name,
            _CLOSE_TIMEOUT,
        )
        task.cancel()

The fix adds bounded task shutdown for MCP sessions and, per the accompanying GitHub Security Advisory GHSA-w3fx-mc44-mf6j, tightens validation of MCP stdio commands.

Detection Methods for CVE-2026-45018

Indicators of Compromise

  • Unexpected POST /mcp requests in Chainlit access logs, especially from external IPs
  • Child processes spawned by the Chainlit process running sh, bash, npx -c, or python -c with unusual argument strings
  • Outbound network connections initiated by subprocesses of the Chainlit worker to unfamiliar destinations
  • Modifications to .chainlit/config.toml or environment variables containing API keys shortly after MCP activity

Detection Strategies

  • Inspect HTTP request bodies for /mcp endpoints and flag fullCommand values containing -c, backticks, shell metacharacters, or piped commands
  • Baseline expected child processes of the Chainlit runtime and alert on any deviation
  • Correlate /mcp request timestamps with process creation and outbound network telemetry to identify command chains

Monitoring Recommendations

  • Enable verbose application logging for the Chainlit MCP subsystem and forward logs to a centralized SIEM
  • Monitor for anomalous process ancestry where the Chainlit Python interpreter spawns interactive shells or package runners
  • Alert on any HTTP 200 responses from /mcp originating from non-allowlisted source networks

How to Mitigate CVE-2026-45018

Immediate Actions Required

  • Upgrade Chainlit to version 2.12.0 or later across all deployments
  • If upgrade is not immediately possible, set features.mcp.enabled = false in .chainlit/config.toml to disable the vulnerable endpoint
  • Rotate any credentials, API keys, or tokens accessible to the Chainlit process, as they may have been exposed
  • Audit HTTP logs for prior POST /mcp requests to determine whether exploitation occurred

Patch Information

The vulnerability is remediated in Chainlit 2.12.0. Review the GitHub Release Version 2.12.0, the GitHub Commit Changes, and the GitHub Security Advisory SPL-2026-001 for full remediation details.

Workarounds

  • Disable the MCP feature entirely by setting features.mcp.enabled = false until patching is complete
  • Restrict allowed_executables to a minimal explicit list and remove any binary that supports inline command evaluation such as npx, bash, sh, or python
  • Place Chainlit behind an authenticating reverse proxy and deny external access to /mcp
  • Run the Chainlit process under a low-privilege service account with no access to sensitive credentials or lateral network paths
bash
# Configuration example: disable MCP in .chainlit/config.toml
[features.mcp]
enabled = false

# If MCP must remain enabled, restrict allowed executables explicitly
[features.mcp.stdio]
allowed_executables = ["my-safe-mcp-binary"]

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.