MCP Server Exposed to the Internet: Attack Surface Analysis

A public MCP server is an unauthenticated RPC endpoint with file access, SSRF, and credential exposure. Full attack surface breakdown and remediation checklist.

MCP Server exposed to the internet: SSRF, file read, and credential access

Exposing an MCP server to the public internet without authentication creates an attack surface that combines the worst properties of an unauthenticated REST API and a server-side request forgery proxy. The server is designed to give an AI agent privileged access to internal resources. When an attacker becomes that agent, every tool is a weapon.

Attack Surface Breakdown

Orb44's outside scan can identify exposed MCP server endpoints and open ports from the public side, without requiring server access or credentials.

SSRF via Tool Calls

Any tool that makes server-side HTTP requests — fetch_url, http_request, browse, search — is an SSRF vector. The MCP server runs inside your network. An attacker calls the tool with internal addresses:

# Probe AWS metadata via an MCP HTTP tool
curl -X POST http://mcp.example.com:8080/mcp \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
       "params":{"name":"http_request",
                 "arguments":{"url":"http://169.254.169.254/latest/meta-data/iam/security-credentials/"}}}'

If the tool returns the response body, the attacker now has IAM role credentials. From there, they can call the AWS API directly with full role permissions.

File Read and Arbitrary Path Traversal

File access tools accept paths. Without chroot or path validation, an attacker reads any file accessible to the server process user:

# Read server's environment file
{"name":"read_file","arguments":{"path":"/proc/self/environ"}}

# Read application secrets
{"name":"read_file","arguments":{"path":"/app/.env"}}

# Read SSH keys
{"name":"read_file","arguments":{"path":"/root/.ssh/id_rsa"}}

Credential Access

MCP servers that proxy to third-party APIs (Stripe, GitHub, Slack, databases) hold those credentials in environment variables or config files. Even if there's no file read tool, a shell execution tool exposes them via env or cat /proc/self/environ. Database tools with connection strings expose the credentials in the tool schema itself — input parameters often include connection_string with a default value pre-filled.

Lateral Movement

The MCP server's network position — inside a VPC, on a developer workstation with VPN access, in a CI runner — determines lateral movement options. Common paths: use the HTTP tool to reach internal admin panels, use the database tool to query production DBs, use shell execution to pivot to other internal services via their CLIs.

Real-World Exposure Patterns

  • n8n workflows — n8n has native MCP node support. Workflows with MCP trigger nodes listen on configurable ports. n8n instances that are already exposed (common in self-hosted setups) often expose the MCP port alongside the main UI.
  • Claude Desktop with remote MCP — Claude Desktop supports remote MCP servers via HTTPS. Developers who want to share a server with teammates sometimes expose it publicly rather than setting up a VPN.
  • Custom FastAPI/Flask implementations — the MCP Python SDK makes it trivial to mount an MCP server on an existing web framework. Developers add it to their API server, which is already public, without considering the security implications.
  • Vercel / Railway / Render deployments — platform-as-a-service deployments of MCP servers are fully public by default. The platform assigns a public HTTPS URL, and without auth middleware, every tool is accessible.

Port and Endpoint Fingerprinting

Shodan and Censys index HTTP services. An MCP server that responds to POST /mcp with a valid JSON-RPC initialize response is distinguishable from generic HTTP services. Shodan queries to find them:

# Shodan search for MCP initialize responses
http.html:"protocolVersion" http.html:"serverInfo"

# Common paths to probe
POST /mcp
POST /api/mcp
GET  /sse
GET  /mcp/sse
POST /rpc

Remediation Checklist

  • ☐ Bind to 127.0.0.1 unless public access is required and authenticated.
  • ☐ Put a reverse proxy (nginx, Caddy, Traefik) in front with Bearer token auth or mTLS.
  • ☐ Implement the MCP OAuth 2.1 spec for any server that needs external access.
  • ☐ Restrict file access tools to a defined chroot directory. Reject .. and absolute paths outside the root.
  • ☐ Block SSRF in HTTP tools: deny RFC 1918 ranges (10.x, 172.16–31.x, 192.168.x), loopback, and cloud metadata IPs (169.254.169.254, fd00::ec2).
  • ☐ Run the server process as a non-root user with minimal filesystem permissions.
  • ☐ Disable or remove any shell execution tools in production.
  • ☐ Log every tool invocation with the caller's IP, arguments, and response size.
  • ☐ Set a firewall rule to allow only known AI host IPs to reach the MCP port.

FAQ

My MCP server requires an API key in the HTTP header. Is that enough?

It depends on how the key is validated and distributed. A single shared secret that all users know is one compromised developer away from full exposure. Use per-client tokens with rotation and revocation. Log all authentication failures — repeated failures against a public endpoint indicate active probing.

Can I use Cloudflare Access to protect an MCP server?

Yes. Cloudflare Access with a Service Token provides strong authentication for machine-to-machine connections. The AI host sends the service token in CF-Access-Client-Id and CF-Access-Client-Secret headers. This works well for HTTP transport MCP servers.

Does TLS (HTTPS) protect an MCP server?

TLS encrypts the connection but provides no authentication. An attacker can call an HTTPS MCP server just as easily as an HTTP one — the protocol the attack uses is the same. TLS prevents eavesdropping; it does not prevent unauthorized access.

Orb44 Journal · all posts