HOME Resources Blog MCP Defaults Will Betray You: The Hidden Dangers of Remote Deployment

|

MCP Defaults Will Betray You: The Hidden Dangers of Remote Deployment

The Model Context Protocol (MCP) enables seamless integration between large language models (LLMs) and external tools. It powers agent-driven workflows in platforms like Claude Desktop and GitHub Copilot. Typically, developers use MCP servers to expose internal tools, such as file readers, database connectors, or shell wrappers, through standardized interfaces.

However, a critical oversight in one of its most widely adopted implementations – FastMCP,can expose entire environments to unauthenticated remote code execution (RCE). By default, FastMCP allows HTTP deployment with no authentication or encryption. In today’s landscape, where spinning up an MCP server is a trivial task, this becomes a dangerous default.

This article demonstrates how I followed the official FastMCP documentation to build a standard remote MCP server, revealing how the default setup permits unauthenticated access to internal tools, and ultimately, arbitrary command execution.

Background

FastMCP is a lightweight MCP server implementation widely used for prototyping and integration testing. It simplifies tool interactivity by providing a plug-and-play HTTP interface for LLM agents that was introduced in version 2.3.0. 

But that convenience comes at a cost:

  • No authentication by default
  • No encryption, HTTP by default without a built in option for HTTPS.

These insecure defaults put organizations at risk if the server is publicly accessible.

MCP Architecture & Transport Overview

In this article, I will use the Python-based FastMCP library. MCP enables LLM agents to interact with external tools through a server and transport layer. A typical setup includes:

  • MCP Server – Hosts tool definitions and handles agent communication.
  • Agent – Sends user input, selects tools, and handles responses.
  • Transport Layer – The protocol used to facilitate communication.

Supported Transport Mechanisms

FastMCP supports several transport methods:

  • stdio – Local synchronous execution
  • sse – Server-sent events for async browser workflows
  • http / streamable-http – Remote HTTP access (added in v2.3.0)

While stdio and sse are appropriate for local or browser-based use, http and streamable-http are commonly used for remote deployments, where misconfiguration poses a significant risk.

The official documentation recommends starting with:

from fastmcp import FastMCP

mcp = FastMCP()

if __name__ == "__main__":
    mcp.run(transport="http")

The Problem

Here’s how a common misconfiguration can lead to a serious security risk:

  1. Developers define tools and deploy the remote FastMCP server with transport=”http” and host=”0.0.0.0″.
  2. There is no authentication or encryption in this setup.
  3. Anyone with the server’s public IP and port can access its endpoint and connect agents to the MCP server.
  4. Once the agent is connected to the server, the agent can invoke any exposed tool by just sending queries in native language.
  5. If a tool provides access to the file system or shell, without input validation, this results in unauthenticated RCE.
  6. Because the traffic is unencrypted (HTTP), it’s also vulnerable to interception or modification.

These issues are noted in the MCP transport documentation, but not enforced by the implementation of FastMCP.

Proof of Concept (PoC)

To demonstrate this, I created the following FastMCP server and deployed it on an Azure VM:

from fastmcp import FastMCP

mcp = FastMCP("FastMCP Exploit Demo", host="0.0.0.0", port=8000)

@mcp.tool
def read_file(path: str) -> str:
    """Reads the contents of a file."""
    with open(path, 'r') as f:
        return f.read()

@mcp.tool
def run_shell(cmd: str) -> str:
    """Runs a shell command."""
    import subprocess
    return subprocess.getoutput(cmd)

@mcp.tool
def list_dir(path: str = ".") -> list:
    """Lists files in a directory."""
    import os
    return os.listdir(path)

if __name__ == "__main__":
    mcp.run(transport="streamable-http")

Key points:

  • The server listens on 0.0.0.0:8000 with no auth or TLS.
  • It exposes tools commonly used in real MCP environments like “read_file”,”list_dir”.
  • The run_shell tool exposes a major risk. It accepts unvalidated shell commands that can lead to Remote Code Execution.

These tools could easily be extended to interact with databases, internal APIs, or file shares – further expanding the attack surface.

Attacker Setup

On a separate machine, I launched GitHub Copilot in Agent Mode and pointed it to the MCP endpoint with the following format: http://<public-ip>:<defined-access-port-like-8000>/mcp/The agent connected instantly – no token, no handshake, no verification.
After adding the MCP server, it was added to the following json file. This file defines all MCP servers for the agent, in our case GitHub Copilot, and it is used as context.

From there, I could invoke any tool on the server by sending queries in native language, including those with shell or file access. Because user input isn’t sanitized, remote command execution was trivial.

The read_file tool and list_dir are also invoked in the same way:

This is the HTTP request sent by the agent to the server, captured using Wireshark. As shown, it is a plain, unencrypted HTTP request. You can see the POST request directed to the MCP server on port 8000, along with the shell command I executed on the server (whoami in this case). 

Detection

To identify potential misuse or compromise:

  1. Monitor network traffic to and from your MCP server.
  2. If authentication is implemented, detect any attempts to access the server using unauthorized or invalid credentials, including failed login attempts, token misuse, or access from suspicious IP addresses.
  3. Enable logging on the MCP server and flag anomalous tool usage (e.g., shell commands, sensitive file reads).

Mitigation

To secure your MCP deployment:

  1. Enforce Authentication: Require proper authentication mechanisms for every incoming connection to ensure only authorized access. On the server side, implement a TokenVerifier as defined in the official MCP docs or in the official FastMCP docs (relevant only for version 2.11.0 or newer). On the agent side, if you are using a vendor-managed agent like GitHub Copilot, configure it to use Bearer Token Authentication as described in the official FastMCP documentation (relevant only for version 2.6.0 or newer)
  2. Enable HTTPS: Always deploy services over HTTPS/TLS in production to encrypt traffic and protect data in transit. Since FastMCP doesn’t provide an option to implement the MCP server with HTTPS directly, you need to add it externally by yourself. There are multiple ways to do that, one is described here.
  3. Avoid integrating insecure tools: Do not deploy tools that have privileged access to the host, such as shell execution unless they include proper input validation and sanitization.
  4. Restrict Network Binding: Avoid 0.0.0.0; bind to localhost or internal IPs.
  5. Restrict Network Access: Ensure the MCP server’s port is not exposed via a permissive policy and is accessible only from explicitly allowed hosts.
  6. Harden Session Handling: Use cryptographically strong session identifiers and validate them thoroughly to prevent session hijacking.
  7. Check Origin Headers: Inspect and verify the Origin header of all incoming requests to defend against DNS rebinding attacks.

Conclusion

This article underscores the danger of insecure system design, especially in protocols that enable insecure access via LLMs. While the official MCP documentation may include optional warnings, many developers rely on quickstart examples and expect the base implementation to be secure. In the case of FastMCP, that means HTTPS instead of HTTP, requiring authentication, and discouraging public access – before someone else connects first.

Security must be built in, not bolted on.

About The Author

Liora Itkin is a Security Researcher currently working at CardinalOps, where she focuses on detection engineering and threat coverage optimization. She previously worked as a Security Researcher at Palo Alto Networks, in incident response at a leading MDR company, and in an intelligence unit, building a strong foundation in SOC operations and detection strategy. She is particularly interested in advancing detection methodologies and frequently collaborates with the security community through research and knowledge sharing.