CloudCodeTree LogoCloudCodeTree
AI NewsTutorialsAbout
CloudCodeTree Logo
CloudCodeTree
  • AI News
  • Tutorials
  • About
← Back to AI News
Five Attacks That Break MCP Servers — and the Fixes the Official Spec Requires

Five Attacks That Break MCP Servers — and the Fixes the Official Spec Requires

Chris Harper

4 min read

Jul 13, 2026 · 04:05 UTC

AI
Workflow
MCP
Security
Agents

The official MCP Security Best Practices guide documents five attack classes exploitable against production MCP servers right now. If you ship an MCP server, at least three of these apply to you.

The Model Context Protocol Security Best Practices is the authoritative reference — published by the MCP spec authors, not a third-party advisory. Here are the five attacks and their required mitigations.

1. Confused Deputy (proxy servers)

If your MCP server proxies to a third-party OAuth API using a static client_id, an attacker can register a malicious MCP client and craft an authorization request that reuses the user's existing consent cookie. The third-party auth server skips the consent screen (cookie present) and redirects the authorization code to the attacker's redirect_uri.

Fix: Add a per-client MCP-level consent screen before forwarding to the third-party auth server. Store consent decisions server-side keyed by client_id. Validate redirect_uri with exact string matching (no wildcards). Generate a cryptographically random state per request and store it only after consent is approved.

2. Token Passthrough

Forwarding a token from the MCP client directly to the downstream API (without validating it was issued to your MCP server) lets clients bypass your rate limiting, logging, and audit trail. The spec explicitly forbids this.

Fix: Validate the aud (audience) claim on every inbound token. Reject tokens not issued for your MCP server. Issue fresh, scoped tokens for downstream services — the LLM should never see a raw downstream secret.

3. Server-Side Request Forgery (SSRF)

During OAuth metadata discovery, your MCP client fetches URLs from the server response (resource_metadata, authorization_endpoint, etc.). A malicious server can inject URLs pointing to cloud metadata endpoints (169.254.169.254) or internal services to exfiltrate credentials.

Fix:

import ipaddress, urllib.parse

BLOCKED_RANGES = [
    ipaddress.ip_network("10.0.0.0/8"),
    ipaddress.ip_network("172.16.0.0/12"),
    ipaddress.ip_network("192.168.0.0/16"),
    ipaddress.ip_network("169.254.0.0/16"),  # cloud metadata endpoints
    ipaddress.ip_network("127.0.0.0/8"),
]

def is_safe_oauth_url(url: str) -> bool:
    parsed = urllib.parse.urlparse(url)
    if parsed.scheme != "https":
        return False
    try:
        addr = ipaddress.ip_address(parsed.hostname)
        return not any(addr in net for net in BLOCKED_RANGES)
    except ValueError:
        return True  # hostname — apply DNS pinning separately

For server-side MCP clients, use an egress proxy (e.g., Stripe's Smokescreen) that blocks internal destinations at the network layer.

4. Session Hijacking

If you use a shared session queue (for resumable streams) keyed only by session ID, an attacker who guesses a session ID can inject malicious events that get delivered to the legitimate client.

Fix: Generate session IDs with a cryptographically secure RNG (UUID v4 minimum). Store queue data keyed by <user_id>:<session_id> — even a guessed session ID is useless without the user ID derived from the validated token. Rotate session IDs and set short expiry.

5. OAuth Authorization URL Injection

A malicious MCP server can provide a javascript: URL as the authorization endpoint, or a URL with shell-injection payloads. If your client opens it with a shell command (os.system, subprocess.run(shell=True)), the attacker gets XSS or remote code execution.

Fix:

from urllib.parse import urlparse

def validate_auth_url(url: str) -> str:
    parsed = urlparse(url)
    # Only https in production; http only for loopback dev
    if parsed.scheme not in ("https",):
        raise ValueError(f"Dangerous URL scheme: {parsed.scheme!r}")
    return url

Never use os.system(f"open {url}") or subprocess.run(f"xdg-open {url}", shell=True). Use webbrowser.open(url) — it bypasses the shell entirely.

Bonus: Scope Minimization

Start with the narrowest useful scope (e.g., mcp:tools-basic) and use WWW-Authenticate scope challenges for progressive elevation. Publishing all scopes in scopes_supported or using wildcards (*) expands the blast radius of every stolen token.

The full spec also covers local server sandboxing, CSRF protection on consent UIs, and __Host- prefix requirements for consent cookies — worth the full read if you're shipping a production MCP server.

Sources: MCP Security Best Practices — modelcontextprotocol.io · Security Design Considerations for AI-Driven Automation — NSA/CISA CSI · Secure MCP Server Development Guide — OWASP