A malicious MCP server can return an authorization URL that runs script or shell commands when a careless client opens it. Clients must accept only http and https, reject other schemes, and open URLs without a shell. These are small code changes that remove a serious attack path.
How the attack works
During the OAuth flow, MCP servers hand clients an authorization URL to open in a browser. The MCP security best practices describe two abuses of weak handling.
JavaScript URL injection: the server supplies a URL beginning with the javascript scheme. The client passes it to a browser API like window.open, and the code runs inside the client application. That can lead to session hijacking or credential theft.
Command injection: the server supplies a URL with shell syntax in it. If the client opens URLs by calling cmd.exe, PowerShell or a shell script, parts of the URL are read as commands. The result is arbitrary code execution as the user.
The escalation path
The specification also describes a chain. If an attacker gets script running in a client that uses a local proxy to start stdio servers, they can read the proxy's authentication token and ask it to spawn arbitrary commands. Web level XSS becomes code execution on the machine. The specification notes this applies to proxy architectures, not to direct stdio use.
Required client behavior
The specification uses strong language here.
- Only allow
http://andhttps://for authorization URLs. Plain http is acceptable only for loopback during local development. - Reject javascript, data, file, vbscript and other dangerous schemes. Use an allowlist rather than a blocklist.
- Do not use shell commands to open URLs. Use the platform's own non-shell mechanism.
- Sanitize and strictly parse every URL received from a server, and reject special characters a shell might interpret.
- Log suspicious authorization URLs for monitoring.
Web based clients should add a Content Security Policy, for example restricting script sources to the same origin.
Limiting the damage
Since XSS compromises the client's security context, the specification suggests defense in depth: sandbox or containerize processes the proxy spawns, restrict their file system access, log all stdio usage, require extra authorization for dangerous commands, and run the proxy itself with least privilege.
Test it
Point your client at a test server that returns three authorization URLs: one with a javascript scheme, one with a file scheme, and one with an ampersand and a command after it. All three should be rejected or opened as inert text, and none should execute anything.
Where Safeguard fits
Safeguard includes dependency scanning and SAST code scanning. They help you find known vulnerable libraries in a client you ship. The URL handling rules above still have to be written into the client.
Quick check
Is a blocklist of bad schemes enough?
The specification says to prefer allowlists. Blocklists miss schemes you did not think of, while an allowlist of http and https fails closed.
Sources
Last reviewed: 19 October 2026.