MCPSafe.io
RegistryThreatsMethodologyDocsPricingScanSign in
MCPSafe.io

Security checks for MCP servers — public packages and private repos, fast or deep.

Legal

Privacy PolicyCookie PolicyTerms of ServiceSecurity disclosure

Resources

State of MCP SecuritySupportSystem statusMade in Germany 🇩🇪

© 2026 MCPSafe. All rights reserved.

GDPR — Privacy Policy
← Threat Catalog

Server Implementation

OAuth Metadata Passed to Process Spawn

HIGHCWE: CWE-78Rule: MCP-275

MCP proxies that pass raw OAuth authorization-server metadata fields (authorization_endpoint, token_endpoint, jwks_uri) into subprocess or child_process calls allow a malicious upstream MCP server to achieve remote code execution on the client.

What it is

This is an OS command injection vulnerability (CWE-78) where an OAuth discovery document — a JSON blob fetched from an attacker-controlled MCP server — supplies endpoint URLs that are then handed unmodified to a process spawn API. Even with `shell=False` and list-style argv (which prevents classic shell metacharacter injection), URLs like `--upload-pack=evil` or `--config=...` are interpreted by the spawned binary as flags, giving the attacker arbitrary-flag injection against tools like git, curl, or aws.

Why it matters for MCP

This is the exact CVE-2025-6514 (`mcp-remote`) attack class: an MCP proxy fetches `/.well-known/oauth-protected-resource` from a malicious server, then passes `authorization_endpoint` to `subprocess.run(["git", "clone", url])` — and gets RCE the moment the URL is `--upload-pack=evil-script`. MCP-275 is intentionally narrower than the generic command-injection rule (MCP-002): it catches the case where developers correctly avoid `shell=True` and string concatenation but still flow OAuth metadata fields into argv as bare elements. Because OAuth discovery is a routine part of every authenticated MCP integration, every proxy or client that forwards these endpoints is in scope.

Vulnerable example

example.py
1
import subprocess
2
from mcp.server import Server
3
4
srv = Server("proxy")
5
6
def handle_oauth(metadata):
7
    # VULNERABLE: discovery doc field passed straight into argv —
8
    # attacker controls the URL, so attacker controls the flag.
9
    authorization_endpoint = metadata["authorization_endpoint"]
10
    subprocess.run(["git", "clone", authorization_endpoint], check=True)

Secure example

example.py
1
import subprocess
2
from urllib.parse import urlparse
3
from mcp.server import Server
4
5
srv = Server("proxy")
6
ALLOWED_HOSTS = {"auth.example.com", "auth.partner.example.com"}
7
8
def handle_oauth(metadata):
9
    parsed = urlparse(metadata["authorization_endpoint"])
10
    if parsed.scheme != "https":
11
        raise ValueError("must be https")
12
    if parsed.hostname not in ALLOWED_HOSTS:
13
        raise ValueError("untrusted host")
14
    # `--` separator prevents flag injection even if URL parsing is bypassed.
15
    subprocess.run(["git", "clone", "--", parsed.geturl()], check=True)

How MCPSafe detects this

MCPSafe fires per-occurrence on a single line when ALL three conditions hold: (1) the file is in MCP context (`@modelcontextprotocol/sdk`, `from mcp`, `FastMCP`, or `McpServer`); (2) the same line contains both a process-spawn call (`subprocess.run/Popen/call/check_output`, `child_process.spawn/exec/execFile/spawnSync`, `os.system`, `exec.Command`) AND an OAuth metadata field identifier (`authorization_endpoint`, `token_endpoint`, `jwks_uri`, `registration_endpoint`, `revocation_endpoint`, `userinfo_endpoint`, `device_authorization_endpoint`, `introspection_endpoint`, `end_session_endpoint` — both snake_case and camelCase); (3) no same-line URL-validation marker is present. Markers that silence the finding include `urlparse`, `new URL()`, `validate_url`, `validators.url`, `is_https_url`, `assert_https`, and `shlex.quote`. The rule is disjoint from MCP-002 (shell=True / string concatenation) and MCP-060 v2 (OAuth metadata SSRF) — all three can co-fire informatively when the same file mixes failure modes.

See the full threat catalog for every documented detection.

Further reading

  • CVE-2025-6514 — mcp-remote OAuth metadata RCE
  • LiteLLM — MCP stdio Command Injection (April 2026)
  • CWE-78: OS Command Injection
  • OWASP — Command Injection

Scan an MCP server for this issue

MCPSafe runs this check — and every other rule in the catalog — on any MCP server you paste in.

Scan now