FlawOpen

flawopen.com/Teardowns/cve-2026-105697-langflow-mcp-stdio-command-injection

● CVE-2026-105697 · CVSS 9.9[1] · Critical
FlawOpen Security Research

CVE-2026-105697: Langflow MCP Command Injection

Before 1.10.3, Langflow passed MCP stdio configuration to a shell-backed process. On an exposed instance with LANGFLOW_AUTO_LOGIN=true, an attacker could obtain a token without credentials; with auto-login disabled, an authenticated non-admin could still reach host command execution. Version 1.10.3 validates every path, including immediately before spawn, and launches without a shell.[1], [2], [3]

CVSS vectorCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H[1]
💡 Plain English Explainer (ELI5)

Imagine a clerk given a sentence where punctuation can change the job: one mark can turn a delivery instruction into a second order. Langflow sent the configured command through a shell that interprets such syntax as control, instead of treating the executable and arguments as separate data. The fix validates the permitted command and launches it directly without a shell.[1], [2]

Core Concepts & Subsystem Terms

MCP stdio transport
Starts an MCP server as a local child process and exchanges protocol messages over standard input and output.[1], [2]
Command injection (CWE-78)
Externally influenced text alters the operating-system command sent to a shell or process launcher.[1], [5]
Execution sink
The final code path that creates a process; validation must hold here even when earlier API checks exist.[1], [2]
Embedded flow/tweak configuration
MCP settings carried inside a flow or runtime override rather than created through the settings API.[1], [2]

Framework mappings

  • CWE reference for the weakness described in this guide: CWE-78

Root Cause Analysis

Before 1.10.3, MCP stdio setup built a command string from configured command and arguments, then launched bash -c with that string. The settings API gained allowlist and argument/environment checks in 1.9.0, but embedded MCP Tools flow or tweak configurations could bypass that model validation because the execution sink had no shared policy. Langflow 1.10.3 centralizes validation in lfx.base.mcp.security.validate_mcp_stdio_config, applies it to API, flow, tweak, legacy component, and pre-spawn paths, and removes the shell wrapper. CVE-2026-105697 is CWE-78, CVSS 3.1 9.9. With auto-login disabled, exploitation still requires an authenticated non-admin user able to configure or execute the relevant MCP path; default auto-login can make exposed development instances reachable without credentials.[1], [2], [4], [5]

Step-by-Step Attack Flow

Step 1

User reaches an MCP configuration path

The advisory describes access through MCP server settings or a flow using the MCP Tools component. On an exposed instance with the development-only default LANGFLOW_AUTO_LOGIN=true, an attacker could obtain a token without credentials. With auto-login disabled, an authenticated non-admin can still be sufficient.[1]

Step 2

Configuration reaches process setup

The command and arguments become command_str while Langflow prepares an MCP stdio connection.[1]

Step 3

Shell wrapper interprets the string

Before 1.10.3, the launch path used bash -c; execution occurred when Langflow tried to connect, before a successful MCP handshake.[1]

Step 4

Entry-point checks are incomplete

Version 1.9.0 validates REST settings, but flow and tweak configurations can bypass that model-level validation.[1]

Step 5

Host process runs with Langflow privileges

The command executes as the Langflow service user. The UI may still report that the MCP server failed to start.[1]

Step 6

1.10.3 closes the execution boundary

A shared policy validates configurations at each entry point and immediately before spawn; the program is launched without a shell.[1], [2]

Source Code: Flaw vs. Secure Implementation

The vulnerable excerpt shows the shell-backed launch shape documented by the advisory, not a runnable exploit. The hardened excerpt is a source-shaped reduction of the 1.10.3 design: a shared policy validates the configuration at every entry point and again immediately before spawning, while the process API receives executable and arguments separately. Direct spawning removes shell interpretation, but does not alone make every allowed executable or package safe; operators must also apply package-source and isolation controls appropriate to their deployment.[1], [2]

Source excerpt: lfx/base/mcp/util.py — focused source-shaped excerpts

UNPATCHED FLAW
# Affected launch shape from the advisory (focused excerpt):
server_params = StdioServerParameters(
    command="bash",
    args=["-c", f"exec {command_str}"],
    env=env_data,
)
HARDENED SECURE PATCH
# 1.10.3 source-shaped reduction: validate the policy, then spawn directly.
command_parts = shlex.split(command_str)
if not command_parts:
    raise ValueError("MCP stdio command is required")
command, args = command_parts[0], command_parts[1:]
validate_mcp_stdio_config(command, args, env_data)  # Repeat at the execution boundary.
server_params = StdioServerParameters(
    command=command,
    args=args,
    env=env_data,
)  # No shell wrapper. The shared validator rejects disallowed configurations.

Engineering & System Hardening Checklist

Sources