PUBlished on
September 30, 2025
updated on
November 5, 2025

From .well-known to Well-Pwned: Common Vulnerabilities in AI Agents

Gavin Zhong and Shuyang Wang

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.

MCP Authorization Sequence Diagram (from MCP Draft Specification §2.3.3)

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.

Command Injection in the Open Library

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.

Command Injection Threat Model Diagram

Command Injection in Cherry Studio, CVE-2025-54074

Command Injection in Gemini-CLI

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.

Windsurf vulnerable to local file execution during MCP authorization flow

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.

VS Code RCE in a remote MCP Authorization Flow

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.

Cross-Site Scripting Threat Model Diagram

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.)

Insecure MCP Authorization Flow leads to Cookie Stolen in Smithery.ai

MCP Authorization Flow leads to Data Exfiltration in Lutra.ai

Insecure MCP Authorization Flow leads to Token Stolen in Glue.ai

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.

Insecure MCP Authorization Flow leads to Chained RCE in MCP Inspector

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.

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.

Frequently Asked Questions (FAQs)

What vulnerabilities were discovered in popular MCP clients related to AI agent security?

Obsidian Security identified critical vulnerabilities in widely used MCP clients—including Gemini-CLI, Cherry Studio, VS Code, Windsurf, Smithery.ai, Lutra.ai, and Glue.ai—that allow Remote Code Execution (RCE), Local File Execution (LFE), and Account Takeover (ATO). These flaws stem from insecure handling of authorization flows, especially when opening URLs without proper sanitization, making client environments highly susceptible to compromise from malicious or manipulated servers.

How does the new MCP authorization specification introduce security risks?

The updated MCP authorization spec leverages OAuth 2.0 Protected Resource Metadata, allowing MCP servers to advertise trusted authorization servers. This design, while clarifying roles, opens up new threat vectors: if MCP clients insufficiently validate or sanitize authorization server endpoints, attackers can inject malicious URLs, potentially leading to OS command injection, phishing, and other client-side attacks not common in traditional OAuth implementations.

What role do third-party open libraries play in enabling command injection attacks in MCP clients?

Many MCP clients, especially those using TypeScript/Node.js, rely on widely-used third-party libraries like open to launch browsers. Unlike standard libraries with built-in safety, these libraries may not sanitize URLs and are vulnerable to command injection on platforms like Windows if user input is not rigorously validated. Through this weakness, attackers can exploit MCP clients by delivering crafted payloads from a malicious server, enabling Remote Code Execution (RCE) on affected systems.

What are the primary risks for browser-based MCP clients, and how do these differ from desktop clients?

Browser-based MCP clients, such as those built with JavaScript, face significant risks of cross-site scripting (XSS) when handling authorization endpoints. Unlike desktop apps vulnerable to OS-level code execution, browser clients are susceptible to XSS if URLs (like those starting with javascript:) are not properly sanitized. Successful exploitation allows attackers to steal session data, perform actions as the user, or escalate to more severe attacks—potentially even affecting backend components via chained exploits.

You May Also Like

Get Started

Start in minutes and secure your critical SaaS applications with continuous monitoring and data-driven insights.

get a demo