No Input Sanitization, No Warning: The MCP Vulnerability Behind 30+ Disclosures
This post is part of OX Security’s The Mother of All AI Supply Chains research — a comprehensive investigation into one systemic vulnerability at the heart of the MCP ecosystem, covering 30+ disclosures and 10+ CVEs.
- Download the full eBook for the complete findings
- Explore the full advisory
- Read the main story
Root Vulnerability – Anthropic’s modelcontextprotocol
Anthropic’s modelcontextprotocol gives a direct configuration-to-command execution via their STDIO interface on all of their implementations, regardless of programming language.
As this code was meant to be used in order to start a local STDIO server, and give a handle of the STDIO back to the LLM. But in practice it actually lets anyone run any arbitrary OS command, if the command successfully creates an STDIO server it will return the handle, but when given a different command, it returns an error after the command is executed.
This logic opens a wide range of attack surfaces, when combined with user input; as it can allow direct arbitrary command execution with no input sanitization, and no red flags to the developer during implementation.
Our examples show the basic case study using Python, but it reflects the same inherent vulnerability from all other programming languages (TypeScript, Java, Golang, etc…)
Intended behavior
from mcp import StdioServerParameters
server_params = StdioServerParameters(
command="python",
args=["myapp.py"]
)
Bad practice
from mcp import StdioServerParameters
server_params = StdioServerParameters(
command=user_input_command,
args=user_input_arguments
)
Malicious behavior
from mcp import StdioServerParameters
server_params = StdioServerParameters(
command="rm",
args=["-rf", "/"]
)
Our suggestion to Anthropic on this subject was to either have developers pre-configure the allowed commands and letting the user input just choose them from a predefined list, or just even add a boolean flag stating that arbitrary command execution is allowed, but it operates in a “dangerous mode” and input should be sanitized.
from mcp import StdioServerParameters
server_params = StdioServerParameters(
command="python",
args=["myapp.py"],
allow_unsafe_command_execution=True
)Architectural Vulnerability – FastMCP, LangChain
- These family of vulnerabilities inherit their exploit path by using the StdioServerParameters and other functions without any change of the original code, they act as an intermediate proxy between the developer and the stdio command execution while still providing the same logic and behavior.
Architectural Case Study – LangChain’s langchain-mcp-adapters
Similarly to Anthropic’s modelcontextprotocol, LangChain gives a direct configuration-to-command execution via their MultiServerMCPClient interface
Intended usage
import asyncio
from langchain_mcp_adapters.client import MultiServerMCPClient
async def main():
# Define how to launch your server
configs = {
"my_app": {
"command": "python",
"args": ["myapp.py"],
"transport": "stdio",
}
}
# Initialize and connect
async with MultiServerMCPClient(configs) as client:
# Fetch tools to prove connection is active
tools = await client.get_tools()
for tool in tools:
print(f"Connected to tool: {tool.name}")
if __name__ == "__main__":
asyncio.run(main())
Bad practice
import asyncio
from langchain_mcp_adapters.client import MultiServerMCPClient
async def main():
# Define how to launch your server
configs = {
"my_app": {
"command": user_input_command,
"args": user_input_arguments,
"transport": "stdio",
}
}
# Initialize and connect
async with MultiServerMCPClient(configs) as client:
# Fetch tools to prove connection is active
tools = await client.get_tools()
for tool in tools:
print(f"Connected to tool: {tool.name}")
if __name__ == "__main__":
asyncio.run(main())
Servers
- We found 6 official platforms with actual users vulnerable to arbitrary command execution via MCP configurations, either directly or indirectly, and either by having an authenticated user or via an unauthenticated user.
- While multiple servers use the same fundamental issue, each has its own way of implementing and connecting MCPs, we needed to analyze each website’s implementation in order to directly execute a command through the STDIO configuration, by modifying the network request or directly adding an STDIO server
Case Studies: Real-World Exploitation
LettaAI – Authenticated RCE on Production Platform
Letta AI (app.letta.com) is a platform for building stateful AI agents with memory capabilities. Its UI exposes MCP server configuration to authenticated users, but only offers Streamable HTTP and SSE connection types in the interface.
Reviewing the source code revealed a third accepted type: STDIO — with no server-side enforcement preventing its use. We intercepted the outbound “Test connection” request using a simulated man-in-the-middle approach, replaced the streamable-http configuration with a valid STDIO payload, and achieved arbitrary command execution on Letta AI’s production servers.

Watch PoC
LangFlow – Unauthenticated RCE at Scale
LangFlow is an open-source research automation framework which is owned by IBM. While designed for local deployment, over 915 publicly accessible LangFlow instances were found on Shodan.
LangFlow’s Settings interface exposes direct MCP configuration, including STDIO type, with no authentication required. A session token is available to any unauthenticated user, and can be obtained by either opening the Web-GUI or sending a simple network request. An attacker can weaponize this by sending a request to obtain the session token, followed by a crafted MCP configuration network request to the same LangFlow instance – achieving full server takeover, data exfiltration, and more, without ever logging in.
The code execution chain: src/lfx/src/lfx/base/mcp/util.py reads user configuration → passes to Anthropic’s StdioServerParameters → which calls the subprocess command execution.
This issue was disclosed to LangFlow on Jan 11, 2026, and we repeatedly tried to contact LangFlow’s maintainers in various ways throughout January to March, this issue was acknowledged directly only at Mar 18, 2026 inside our GHSA report.

Watch PoC
Flowise – Hardening Bypass
Unlike most affected platforms, Flowise was aware of the STDIO risk and implemented input validation: only specific commands were permitted, and special characters were stripped.
We bypassed their controls in a single step, using npx’s -c flag to pass arbitrary commands through an otherwise-allowed command:
| // Flowise blocks this directly:{ “command”: “touch”, “args”: [“/tmp/pwn”] }// Bypass via npx -c:{ “command”: “npx”, “args”: [“-c”, “touch /tmp/pwn”] } |
The bypass worked. This illustrates that ad hoc input filtering is an insufficient defense when the underlying architecture permits arbitrary subprocess execution.

Watch PoC
Windsurf – Prompt Injection to Local RCE (CVE-2026-30615)
Windsurf is an AI-powered IDE designed for developers. While it runs locally, its MCP configuration file (mcp.json) is writable by the AI agent – making it susceptible to prompt injection attacks that add malicious STDIO MCP entries.
Attack chain:
- Victim visits an attacker-controlled website and copies a prompt that appears legitimate
- The site serves different content to Windsurf’s internal requests — injecting a malicious instruction
- Windsurf receives the malicious prompt and proposes edits to mcp.json — without showing the user what will change – and modifies the file.
- With no further user interaction; a new STDIO MCP entry is added and immediately executes its command on the victim’s machine.

Watch PoC


