Summary
The security research team of Obsidian Security recently uncovered a critical security flaw in many common MCP clients, affecting applications across all platforms and resulting in Remote Code Execution (RCE), Local File Execution (LFE) and Account Takeover (ATO). Our findings impact most mainstream MCP clients, including Gemini-CLI, MCP Inspector, Cherry Studio, VS Code, Windsurf, Smithery.ai, Lutra.ai, Glue.ai, and others. To date, this research has led to 4 CVEs and acknowledge.
This blog post presents our findings, including newly discovered 0-days, real-world demos, and detailed technical explanations. It offers valuable insights for security researchers, application security engineers, developers, MCP authorization protocol contributors, and anyone tracking the rapidly evolving MCP ecosystem in today’s AI Agent-driven landscape.
The New MCP Authorization Spec
The latest MCP Authorization spec was updated on 6/28. In this update, the MCP server’s role in an OAuth infrastructure was clarified as a resource server, removing the burden on MCP servers to implement an authorization server themselves.
To this end, OAuth 2.0 Protected Resource Metadata (RFC9728) has been introduced, enabling MCP servers to delegate an associated authorization server for clients to authenticate and obtain tokens to access resource, such as making a tool call to Google Cloud API.
.png)
This, however, introduced a new threat vector that has never broadly existed in OAuth ecosystems, leading to risks of OS command injection, Remote Code Execution, and Application Account Compromise on the client side.
How MCP Clients Discover Authorization Servers
In an MCP authorization flow, the MCP server acts as a resource server and the latest protocol gives the MCP server the ability to announce their trustsed or supported authorization server via the newly published OAuth 2.0 Protected Resource Metadata (RFC9728) standard.
An MCP server does this by serving an /.well-known/oauth-protected-resource endpoint that includes an authorization_servers array in the returned JSON to indicate its associated authorization servers. The client then discovers the authorization endpoint (typically a login page) by performing another server metadata lookup following RFC8414 Section 3.1 “Authorization Server Metadata Request”, where the authorization_endpoint key-value pair in the authorization server’s .well-known/oauth-authorization-server is fetched for authorization (and .well-known/openid-configuration for authentication).
Once the authorization endpoint is determined, an MCP client typically opens a browser to load that page. There is an obvious phishing risk here. For example, it would be prime place to put a fake login page, and users would tend to trust it by the fact that they trust the remote MCP server. However, this is not the biggest issue. This discovery flow actually opens a backdoor that allows fully compromise of the client host system.

From Metadata to RCE: Breaking Client Hosts
MCP clients are often desktop applications such as Cherry Studio or Windsurf, or command-line programs such as Gemini-CLI and mcp-cli.
To finish an OAuth authorization flow, programs like these running in an OS runtime are required to launch a browser process to render the authorization endpoint. However, without proper sanitization of the endpoint URL, this browser-launching step can lead to OS command injection and Remote Code execution.
The “open” Trap in Third-party Library
To implement browse launching, developers often need to spawn a system process to open a browser application. Many programing languages’ standard libraries provide such APIs, such as Python’s webbrowser, which are generally implemented with inherent security guarantee. However, other languages such as TypeScript lack such a out-of-box API for this, so developers often need to seek for third-party library solutions.
open, for example, is one of the most popular libraries in the TypeScript/Node ecosystem (tens of thousands of npm packages depend on it) and is widely used in MCP client apps. It is adopted by many popular projects such as Gemini-CLI and Cherry Studio. However, few people notice the prominent warning on its npm page that the library makes no security guarantees and that untrusted input must be sanitized before being passed to it.
Through our research in its source code, it is found that its open handler is vulnerable to OS command injection on Windows. Due to its powershell execution runtime invoked during a browser launching, an injected subexpression operator $() in a incompletely encoded URL string can lead to OS command injection.

By scaling this weakness to real MCP client applications, we identified and reported multiple 0-day issues, including Cherry Studio (CVE-2025-54074) and Gemini-CLI (maintained by Google), which were promptly fixed after disclosure. These vulnerabilities can lead to full OS command execution on the client host. Notably, injected commands can be delivered via a remote MCP server, allowing victims to be compromised without their awareness.



Abuse Standard Open Handlers: Local File Execution and Remote Code Execution
Aside from insecure third-party open libraries used in MCP authorization flows, there are also official open APIs in language standard libraries, such as Electron’s shell.openExternal and Python’s webbrowser.open. These standard APIs are not themselves vulnerable to command injection, but, because of their flexible design, can still lead to local file execution or remote code execution under certain conditions.
Under the hood, these open handlers typically invoke OS commands such as start on Windows and open on macOS to dynamically support URL launching. For example, Python’s webbrowser.open implementation on MacOS opens a URL using different AppleScript helpers depending on the protocol scheme, which ensures the resource is handled by an appropriate program. In other words, these APIs are often not limited to opening web pages, but provide a flexible mechanism to process many URL schemes.
A URL (Uniform Resource Locator) indicates a computer resource location. Besides the http: and https: schemes, there are also schemes like file:// and smb:// that allow a program to open a file locally or remotely.
Local File Execution
When open handlers process a URL starting with file://, they will typically open the indicated file resource, which can be abused to achieve local file execution attack. A malicious MCP server could exploit this to execute arbitrary files on the victim’s host machine during an MCP connection.
Though in many cases the OS will show a confirmation window asking for user consent before executing the file, there are “magic” file extensions that bypass these prompts. For example, the .command extension on macOS and the now-deprecated .SettingContent-ms extension on Windows (support removed seven years ago for security reasons) allow script files immediately executed without explicit approval.
In our research, we found that several popular vibe coding IDEs, such as VS Code and Windsurf, are vulnerable to this flaw, exposing users to LFE risks.

Remote Code Execution
Remote code execution can also be achieved thanks to the flexibility that open handlers provide when opening remote resource such as smb://. In this scenario, a victim connects to a malicious MCP server which enforces authorization, then the MCP clients start OAuth metadata discovery processes and attempts to open the supplied Samba URL.
Although OSs often display a security warning before executing a remote file, users may ignore and bypass such warnings due to security fatigue noted by NIST. Furthermore, a remote MCP server normally has no direct access to the client host and only accepts tool calls and returns output via JSON-RPC. The primary attack vector for a remote MCP server to compromise a client host is typically indirect prompt injection. This requires a chain of exploitation of other client-integrated tools and additional information from the client environment to succeed, which is usually very difficult to achieve.

Beyond the Host: XSS, Account/Tenant Takeovers & Chained RCE
In addition to process-based MCP clients, there are also many browser-based client implementations, including web, SaaS and web-based desktop clients. These clients run in a browser runtime, and are primarily powered by javascript, such as MCP inspector and the Smithery.ai MCP playground. Surprisingly, the same insecure “open”/authorization handling patterns also affect browser-based clients, but the resulting risks differ: instead of immediate shell execution, attackers typically obtain DOM-level control (XSS) that can be escalated into greater harm.
Browser-based MCP applications commonly use native browser APIs such as location.href and window.open to load an authorization URL. But, without proper sanitization, a cross-site scripting (XSS) attack could be triggered when attacker controlled remote MCP server supplies URLs starting with the javascript: scheme. The injected JavaScript following the scheme would execute in its parent window context, thus allowing an attacker to access application resources, perform actions on behalf of the user, or steal session cookies and tokens from localStorage.

During our research, we identified such vulnerabilities in three SaaS applications, Smithery.ai, Lutra.ai and Glue.ai, in their MCP client implementations. A malicious server could deliver payloads like javascript:alert(1)// as the associated authorization endpoint during OAuth metadata discovery. Subsequently, if clients lack proper URL sanitization or CSP, they would render the XSS payload, leading to various impacts discussed above. (Note: All three vendors promptly fixed the issues after our disclosure; We appreciate their quick response and collaboration.)
.gif)


Furthermore, self-hosted clients of this type, such as MCP Inspector, often combine front-end and back-end processes throughout MCP workflows. Thus, an XSS payload can hijack the communication channel to the background process, stealthily issue malicious commands while circumventing CSRF and DNS-rebinding defenses, and ultimately lead to RCE.

Mitigations
In spite of the high severity this vulnerability brings into MCP ecosystem, mitigation is actually straightforward.
Typically, the authorization endpoint should never use URL schemes other than http and https, so client applications must restrict accepted URLs to those schemes. Furthermore, client applications should avoid using third-party open handlers that introduce command injection risks or that perform incomplete URL encoding on authorization URLs.
Ideally, developers should implement a secure open handler that only launches a browser process, and ensure that all non–URL-safe characters are properly encoded, either via a self-implemented encoder or a trusted sanitization library such as strict-url-sanitise.
Coordinated Disclosure & Vendor Response
We disclosed these vulnerabilities to all affected vendors between June and August 2025 under a coordinated disclosure process. CVE identifiers including CVE-2025-54074 and three others have been assigned. Most vendors have already issued patches in their latest releases.
.png)
Conclusion
Our research reveals a blind spot in MCP client implementations. While the new authorization spec aims to improve security, it also introduces client-side risks rarely faced by traditional authorization frameworks.
Beyond the cases covered in this post, we’re seeing similar issues appear across the ecosystem, often stemming from insecure code in open-source references. We believe the MCP specification itself should provide clearer guidance on safe client-side URL handling and authorization server discovery. With this post, we hope to help raise the MCP community’s awareness of this widespread implementation pitfall.
.avif)
.avif)
