Tools: Report: The MCP RCE That Anthropic Won't Patch: Your Enforcement Checklist

Tools: Report: The MCP RCE That Anthropic Won't Patch: Your Enforcement Checklist

Why "By Design" Changes the Threat Model

The Attack Surfaces You Are Probably Missing

The Enforcement Checklist

1. Audit Your Current STDIO Command Parameters

2. Build a Command Allowlist

3. Rotate Credentials That Agent Processes Can Access

4. Sandbox Your MCP Services

5. Add Pre-Push SCA for Agent Commits

6. Disable STDIO MCP in High-Risk Environments

7. Monitor Tool Invocation Patterns

What Not to Do

The One Layer That Cannot Be Bypassed via MCP

Share this article Last week, OX Security published a disclosure that should be on every engineering team's radar. A systemic remote code execution vulnerability in Anthropic's Model Context Protocol affects every official SDK: Python, TypeScript, Java, and Rust. The blast radius: 150 million downloads, 7,000 publicly exposed servers, 10-plus CVEs spawned across downstream projects. Anthropic's response: this is expected behavior. The protocol will not be modified. That means the fix has to come from you. This post is the concrete checklist. What the vulnerability does: MCP's STDIO transport mechanism executes commands before validation. The sequence is: receive command, run subprocess, then check if the process was a legitimate MCP server. If it wasn't, an error is returned, but the command has already executed. Whoever controls the content of that command field controls what runs on your machine. When a vendor says a behavior is by design, it terminates the normal patch cycle. There will be no CVE for the core protocol. There will be no SDK update that fixes the root issue. Downstream projects, each with their own CVE (Windsurf CVE-2026-30615, Flowise CVE-2026-40933 CVSS 10.0, LibreChat CVE-2026-22252, MCP Inspector CVE-2025-49596), will patch their individual implementations. Attackers will find new bypasses. The cycle repeats because the underlying architecture is unchanged. Flowise tried application-layer filtering. OX Security bypassed it anyway. This is not a criticism of Flowise. It demonstrates why filtering against an architectural execution model is inherently fragile. The threat model shift: you cannot rely on the MCP ecosystem patching its way to safety. Your team needs controls that operate outside the protocol's trust boundary entirely. Most teams think about MCP security at the server configuration level. The actual attack surfaces are broader: Zero-click IDE injection: A malicious MCP JSON config in a repository gets picked up automatically when your IDE indexes the project. Windsurf and Cursor are both confirmed vulnerable. No user action required. Prompt injection to config: An attacker who can influence model context (via a README, a comment, a file the agent reads) can potentially inject content that leads to malicious MCP server configuration. The model processes the content, the config gets written, STDIO executes it. Marketplace poisoning: Researchers successfully submitted malicious MCP servers to 9 of 11 tested registries without detection. If you are pulling MCP servers from a registry, you are in this attack surface. Slopsquatting via MCP config: MCP configurations reference package names. AI agents suggesting MCP servers can hallucinate package names. Attackers register those names. The STDIO vulnerability converts an install into execution. Work through this in order. Items 1-3 are immediate. Items 4-6 are this week. Item 7 is ongoing. List every STDIO command your MCP configuration specifies and treat each as an untrusted execution surface. For each command field you find: can this value be influenced by external content? If the answer is yes or maybe, add it to your remediation list. The only safe STDIO configuration is one where the set of permitted commands is explicit and minimal. Build an allowlist and reject anything outside it. If your MCP framework supports a validation hook, wire this policy in. If it doesn't, treat the absence of validation as a gap to document and monitor. Assume any credential an MCP-accessible process could have reached is potentially compromised. This includes: API keys in environment variables available to the shell where the agent runs SSH keys loaded into the agent AWS/GCP/Azure credentials accessible via credential files or environment Database connection strings in .env files in scanned directories Rotate anything sensitive. Move to short-lived credentials where possible. Run MCP server processes in an environment with restricted filesystem and network access. The goal is limiting blast radius when something executes that shouldn't. Network isolation is especially important: it breaks the C2 callback that makes most exploit payloads useful. MCP-driven agents write code that eventually gets committed. That code can contain hallucinated package names, known-vulnerable dependencies, or packages a prompt-injected agent was steered toward. None of these are caught by STDIO-level controls. Why this matters specifically for MCP: A prompt-injected agent can be directed to add a dependency with a malicious name. The SCA check validates every package name against the live npm/PyPI registry. A package that doesn't exist, or was registered 3 days ago by an unknown account, gets blocked before the commit reaches your remote. If you run agentic workflows in environments where external content reaches model context (reading issues, processing emails, indexing untrusted repositories), consider disabling STDIO MCP entirely in those environments and using only managed, network-based MCP implementations with explicit authentication. The trade-off is capability for safety. In a sandboxed dev environment with controlled inputs, STDIO is manageable. In a CI pipeline that processes arbitrary pull requests, it is not. Establish a baseline of normal MCP tool call patterns for your workflow, then alert on deviations. Unexpected system commands, file system traversal outside normal working directories, or network calls to unfamiliar endpoints are all indicators of a compromised session. A few approaches that sound right but do not address the root issue: Relying solely on application-layer input filtering. Flowise did this. It was bypassed. The execution model means filtering is always playing catch-up with bypass techniques. Trusting MCP marketplace listings. 9 of 11 tested registries accepted malicious submissions without review. Listing presence is not safety verification. Assuming the model will self-detect the issue. Five AI agent failures, zero self-detections in a 36-day study published this week. The model does not have reliable awareness that it has been manipulated. Waiting for Anthropic to patch the protocol. The "by design" response is definitive. Architecture-level protection has to come from your stack. Every control in this checklist except git-layer enforcement can potentially be circumvented if an attacker gains sufficient control over model context or MCP configuration. But a pre-push hook runs as a separate process, initiated by the git client, with its own execution context. An MCP server cannot instruct a git hook not to run. A prompt-injected agent cannot disable a pre-push check it has no visibility into. That asymmetry is why LucidShark focuses on the git layer: SCA, SAST, secrets detection, and lint checks that run at commit time, outside the agent's execution path, against the actual artifact the agent produced. The MCP RCE changes the threat model for what happens during an agent session. It does not change what happens at the git boundary. Install LucidShark: npm install -g lucidshark then lucidshark init to configure pre-push hooks in under 2 minutes. Scans run locally, no data leaves your machine. lucidshark.com Share on Twitter Share on LinkedIn Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Command

Copy

# Find all MCP config files in your project find . -name "*.json" | xargs grep -l '"command"' 2>/dev/null | grep -i mcp # Or check Claude Code's config location cat ~/.config/claude/mcp_servers.json 2>/dev/null || \ cat ~/Library/Application\ Support/claude/mcp_servers.json 2>/dev/null # Find all MCP config files in your project find . -name "*.json" | xargs grep -l '"command"' 2>/dev/null | grep -i mcp # Or check Claude Code's config location cat ~/.config/claude/mcp_servers.json 2>/dev/null || \ cat ~/Library/Application\ Support/claude/mcp_servers.json 2>/dev/null # Find all MCP config files in your project find . -name "*.json" | xargs grep -l '"command"' 2>/dev/null | grep -i mcp # Or check Claude Code's config location cat ~/.config/claude/mcp_servers.json 2>/dev/null || \ cat ~/Library/Application\ Support/claude/mcp_servers.json 2>/dev/null // .mcp-policy.json — document and enforce this { "allowed_commands": [ "npx", "/usr/local/bin/mcp-filesystem", "/usr/local/bin/mcp-github" ], "blocked_patterns": [ "sh", "bash", "zsh", "fish", "python", "python3", "node", "-weight: 500;">curl", "-weight: 500;">wget", "nc", "ncat" ] } // .mcp-policy.json — document and enforce this { "allowed_commands": [ "npx", "/usr/local/bin/mcp-filesystem", "/usr/local/bin/mcp-github" ], "blocked_patterns": [ "sh", "bash", "zsh", "fish", "python", "python3", "node", "-weight: 500;">curl", "-weight: 500;">wget", "nc", "ncat" ] } // .mcp-policy.json — document and enforce this { "allowed_commands": [ "npx", "/usr/local/bin/mcp-filesystem", "/usr/local/bin/mcp-github" ], "blocked_patterns": [ "sh", "bash", "zsh", "fish", "python", "python3", "node", "-weight: 500;">curl", "-weight: 500;">wget", "nc", "ncat" ] } # Audit what's in the environment your agent process inherits env | grep -E "(KEY|SECRET|TOKEN|PASSWORD|CREDENTIAL|API)" | cut -d= -f1 # Audit what's in the environment your agent process inherits env | grep -E "(KEY|SECRET|TOKEN|PASSWORD|CREDENTIAL|API)" | cut -d= -f1 # Audit what's in the environment your agent process inherits env | grep -E "(KEY|SECRET|TOKEN|PASSWORD|CREDENTIAL|API)" | cut -d= -f1 # Example: run MCP server with restricted filesystem via Docker -weight: 500;">docker run --rm \ --read-only \ --tmpfs /tmp \ --network=none \ --cap-drop=ALL \ your-mcp-server:latest # Or use firejail for native processes firejail --noprofile --private --net=none npx @your-org/mcp-server # Example: run MCP server with restricted filesystem via Docker -weight: 500;">docker run --rm \ --read-only \ --tmpfs /tmp \ --network=none \ --cap-drop=ALL \ your-mcp-server:latest # Or use firejail for native processes firejail --noprofile --private --net=none npx @your-org/mcp-server # Example: run MCP server with restricted filesystem via Docker -weight: 500;">docker run --rm \ --read-only \ --tmpfs /tmp \ --network=none \ --cap-drop=ALL \ your-mcp-server:latest # Or use firejail for native processes firejail --noprofile --private --net=none npx @your-org/mcp-server #!/usr/bin/env bash # .-weight: 500;">git/hooks/pre-push echo "Running LucidShark pre-push checks..." # SCA: validate all dependencies against live registry lucidshark scan --sca --block-unregistered # Secrets: catch credentials that leaked into the diff lucidshark scan --secrets # SAST: catch security anti-patterns the agent introduced lucidshark scan --sast echo "Pre-push checks passed." #!/usr/bin/env bash # .-weight: 500;">git/hooks/pre-push echo "Running LucidShark pre-push checks..." # SCA: validate all dependencies against live registry lucidshark scan --sca --block-unregistered # Secrets: catch credentials that leaked into the diff lucidshark scan --secrets # SAST: catch security anti-patterns the agent introduced lucidshark scan --sast echo "Pre-push checks passed." #!/usr/bin/env bash # .-weight: 500;">git/hooks/pre-push echo "Running LucidShark pre-push checks..." # SCA: validate all dependencies against live registry lucidshark scan --sca --block-unregistered # Secrets: catch credentials that leaked into the diff lucidshark scan --secrets # SAST: catch security anti-patterns the agent introduced lucidshark scan --sast echo "Pre-push checks passed." # Log all MCP tool invocations if your framework supports it # Claude Code example: check session transcript for unexpected tool calls grep -A2 '"tool_name"' ~/.config/claude/sessions/*.json | \ grep -v -E "(read_file|write_file|list_directory|bash)" | \ grep "tool_name" # Log all MCP tool invocations if your framework supports it # Claude Code example: check session transcript for unexpected tool calls grep -A2 '"tool_name"' ~/.config/claude/sessions/*.json | \ grep -v -E "(read_file|write_file|list_directory|bash)" | \ grep "tool_name" # Log all MCP tool invocations if your framework supports it # Claude Code example: check session transcript for unexpected tool calls grep -A2 '"tool_name"' ~/.config/claude/sessions/*.json | \ grep -v -E "(read_file|write_file|list_directory|bash)" | \ grep "tool_name" - Zero-click IDE injection: A malicious MCP JSON config in a repository gets picked up automatically when your IDE indexes the project. Windsurf and Cursor are both confirmed vulnerable. No user action required. - Prompt injection to config: An attacker who can influence model context (via a README, a comment, a file the agent reads) can potentially inject content that leads to malicious MCP server configuration. The model processes the content, the config gets written, STDIO executes it. - Marketplace poisoning: Researchers successfully submitted malicious MCP servers to 9 of 11 tested registries without detection. If you are pulling MCP servers from a registry, you are in this attack surface. - Slopsquatting via MCP config: MCP configurations reference package names. AI agents suggesting MCP servers can hallucinate package names. Attackers register those names. The STDIO vulnerability converts an -weight: 500;">install into execution. - API keys in environment variables available to the shell where the agent runs - SSH keys loaded into the agent - AWS/GCP/Azure credentials accessible via credential files or environment - Database connection strings in .env files in scanned directories - Relying solely on application-layer input filtering. Flowise did this. It was bypassed. The execution model means filtering is always playing catch-up with bypass techniques. - Trusting MCP marketplace listings. 9 of 11 tested registries accepted malicious submissions without review. Listing presence is not safety verification. - Assuming the model will self-detect the issue. Five AI agent failures, zero self-detections in a 36-day study published this week. The model does not have reliable awareness that it has been manipulated. - Waiting for Anthropic to patch the protocol. The "by design" response is definitive. Architecture-level protection has to come from your stack.