MCP-Remote Control: From AI Agent to RCE via CVE-2025-6514
Jan 10, 2026ยท5 min read
Executive Summary (TL;DR)
If you use `mcp-remote` (v0.0.5 - 0.1.15) to connect your LLM or app to an untrusted MCP server, you are vulnerable to RCE. A malicious server can return a poisoned URL containing shell commands in the credentials field (e.g., `user$(calc)`), which the client blindly executes. Update to v0.1.16 immediately.
The `mcp-remote` package, a client for the Model Context Protocol, suffers from a critical command injection vulnerability. By failing to sanitize username and password fields in returned authorization URLs, the package allows malicious servers to execute arbitrary shell commands on the client machine.
The Hook: When Agents Talk to Strangers
The Model Context Protocol (MCP) is the new shiny object in the AI world. It's the standard way to connect Large Language Models (LLMs) to external data sources and tools. Naturally, developers need a way to connect to these sources remotely, and that's where mcp-remote comes in. It acts as the client, shaking hands with remote servers to fetch context for your AI.
But here is the problem with "shaking hands" on the internet: sometimes the other person has a joy buzzer hidden in their palm that executes rm -rf /. The core issue here is trust. When mcp-remote connects to a server, it expects that server to behave. Specifically, when the server says, "Hey, authenticate over here at this URL," the client dutifully obeys.
This vulnerability exploits that obedience. It turns a standard authentication redirect into a full-blown Remote Code Execution (RCE) scenario, all because the developer assumed that a URL is just a URL, and not a vehicle for shell commands.
The Flaw: Selective Sanitization
The root cause of CVE-2025-6514 is a classic case of "Sanitization Theater." The developers knew that URLs could be dangerous. They implemented a function called sanitizeUrl in src/lib/utils.ts. They clearly spent time on it.
They scrubbed the pathname. They scrubbed the searchParams. They even scrubbed the hash. They were meticulous about ensuring that if you put weird characters in the path, they got encoded. It's like building a fortress with 10-foot steel walls but leaving the front gate unlocked and wide open.
The one part of the URL they didn't touch? The User Information subcomponents: username and password. In the URL specification (and the Node.js URL object), you can embed credentials like this: http://user:pass@domain.com.
Because these fields were left raw and unescaped, and because this URL is eventually passed to a context that invokes a shell (likely via a subprocess call to handle the auth flow), any shell metacharacters placed in the username or password get executed by the operating system. It is a textbook command injection via untrusted input.
The Code: The Smoking Gun
Let's look at the fix to understand the break. The patch (Commit 607b226) is embarrassingly simple, highlighting just how glaring the omission was. The developer had to manually go back and ensure the credentials were encoded before processing the URL.
Here is the logic flow. Notice the new additions marked with +:
export function sanitizeUrl(raw: string) {
// ... existing checks ...
if (url.hostname !== encodeURIComponent(url.hostname)) abort()
// The fix: Forcibly sanitise the previously ignored pieces
+ if (url.username) url.username = encodeURIComponent(url.username)
+ if (url.password) url.password = encodeURIComponent(url.password)
// The existing code that gave a false sense of security
url.pathname = url.pathname.slice(0, 1) + encodeURIComponent(url.pathname.slice(1)).replace(/%2f/ig,'/')
url.search = url.search.slice(0, 1) + Array.from(url.searchParams.entries()).map(sanitizeParam).join('&')
url.hash = url.hash.slice(0, 1) + encodeURIComponent(url.hash.slice(1))
}Before those two lines were added, url.username was passed through verbatim. If url.username was $(calc), the downstream system saw a command substitution request rather than a username.
The Exploit: Popping Shells via Auth
Exploiting this requires a bit of social engineering or a supply chain attack configuration, but technical execution is trivial. The attacker sets up a malicious MCP server. When the victim (the mcp-remote client) connects, the flow looks like this:
- Victim: Connects to
mcp://evil-server.com. - Attacker: Returns a response indicating that authentication is required at a specific endpoint.
- The Payload: The attacker crafts the
authorization_endpointURL to include the payload in the credentials.
Payload Example:
http://user$(calc):password@attacker.com
When mcp-remote processes this URL to handle the authentication step, the presence of $(...) (command substitution) or backticks triggers execution. If you are on Windows, calc.exe pops up. If you are on Linux, $(whoami) runs.
Here is the attack flow visualization:
The Impact: Why This Matters
This is rated Critical (9.6) for a reason. It requires no authentication to exploit (the attacker is the one doing the authenticating) and results in total compromise of the host application's environment.
Consider the context: mcp-remote is often used by AI Agents. These agents often have access to sensitive keys, databases, and internal APIs. If an attacker gains RCE on the agent's host, they don't just get the server; they get everything the AI has access to.
Since this runs on the client side (the machine initiating the connection), it can breach firewalls. An internal developer connecting to an external "cool new tool" MCP server could inadvertently bridge their internal network to the attacker.
The Fix: Remediation
The fix is available in version 0.1.16. If you are running anything from 0.0.5 to 0.1.15, you are vulnerable.
Immediate Steps:
- Update:
npm install mcp-remote@latest. - Audit: Check your logs for connection attempts to unknown or suspicious domains.
- Restrict: If you are building tools on top of MCP, ensure your agents are not allowed to connect to arbitrary user-defined URLs without a whitelist.
The patch simply ensures that encodeURIComponent is applied to the username and password, neutralizing the special characters required for shell injection.
Official Patches
Fix Analysis (1)
Technical Appendix
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:HAffected Systems
Affected Versions Detail
| Product | Affected Versions | Fixed Version |
|---|---|---|
mcp-remote geelen | >= 0.0.5 < 0.1.16 | 0.1.16 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-78 (OS Command Injection) |
| CVSS Score | 9.6 (Critical) |
| Attack Vector | Network |
| EPSS Score | 0.00727 (72nd Percentile) |
| Exploit Status | PoC Available |
| Patch | Commit 607b226 |
MITRE ATT&CK Mapping
Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
Known Exploits & Detection
Vulnerability Timeline
Subscribe to updates
Get the latest CVE analysis reports delivered to your inbox.