Docker MCP Gateway security model

July 6, 2026 ยท View on GitHub

Docker MCP Gateway is a security boundary between MCP clients and the MCP servers that the gateway runs or connects to. The gateway is designed to reduce what a malicious or compromised MCP server can read, receive, log, or route through the host.

This document describes the default security boundaries for the Docker MCP Gateway and how we triage vulnerability reports. A report is usually in scope when an untrusted catalog entry, remote server, image label, or MCP server can bypass one of the boundaries below without the user or operator explicitly granting that access.

Trust assumptions

  • The local OS user, Docker daemon, Docker Desktop components, configured credential store, configured interceptors, and local Docker MCP configuration files are trusted. An attacker who can modify those inputs can change gateway behavior and is outside this boundary.
  • A catalog, profile, server entry, OCI image label, MCP registry entry, README URL, or remote MCP server URL may be untrusted. The gateway should treat those values as data and must not let them expand into broader host, network, secret, or routing access.
  • The code inside an enabled MCP server may be malicious. It should only receive the environment variables, secrets, filesystem mounts, network access, and MCP routing access granted by the gateway configuration and defaults.
  • Docker's MCP Catalog build-time review, dependency scanning, malware scanning, and publishing process are separate from this repository. Bypasses of those processes should be reported against the catalog or publishing system. Bypasses of gateway enforcement are in scope here.

Gateway boundaries

HTTP transports

The default stdio transport is local to the launching MCP client. When the gateway is run with the sse or streaming HTTP transports, requests require a Bearer token by default. The token is read from MCP_GATEWAY_AUTH_TOKEN when set or generated by the gateway. --allow-unauthenticated is an explicit opt-out.

Browser requests with an Origin header are accepted only from localhost origins (localhost, 127.0.0.1, or ::1). Requests without an Origin header remain allowed so non-browser MCP clients can connect. The /health endpoint is not an MCP protocol endpoint and is intentionally unauthenticated.

Catalogs, local files, and OCI metadata

Catalog paths supplied to gateway commands must resolve under ~/.docker/mcp/catalogs/. Local file:// server references are also resolved relative to that trusted catalog directory, including symlink containment checks, before a file is opened.

OCI image labels are treated as import metadata only. Labels may provide descriptive server and tool metadata, but they must not inject runtime-shaping fields such as commands, volume mounts, secrets, environment values, users, or nested container configuration. Those fields must come from trusted catalog or user configuration paths.

Remote URLs and untrusted fetches

Remote MCP URLs and untrusted HTTP fetches require public HTTPS destinations by default. The gateway rejects userinfo, unsafe hostnames, loopback, private, link-local, metadata-service, and other non-public IP ranges, and it validates redirect destinations. Guarded direct transports also validate the resolved destination at dial time.

DOCKER_MCP_ALLOW_INSECURE_REMOTE_URLS=1 is a development and test opt-out for local or HTTP endpoints. Reports that depend on this opt-out are out of scope unless they also bypass another documented boundary.

Image verification

Signature verification is enabled by default for Docker MCP images in the Docker Hub mcp/ namespace. Those images must be referenced by digest when verification is enabled, and they are verified before pull or run. --verify-signatures=false is an explicit opt-out.

Third-party images outside Docker MCP's signing namespace are not verified with Docker MCP signatures. Their trust comes from the user's catalog, profile, or operator configuration choice.

Container execution

MCP server containers do not receive the user's host environment by default. The gateway passes only configured environment variables, server config values, and secrets declared for that server. Containers are started with Docker isolation, no-new-privileges, and configured CPU and memory limits.

Host bind mounts from catalog or profile configuration are validated before they are passed to Docker. Named and anonymous Docker volumes are allowed. Host path binds default to read-only, must resolve under trusted roots such as temporary directories or MCP_GATEWAY_DOCKER_BIND_ALLOWED_PATHS, and cannot target known sensitive system or credential paths. Writable host path binds require an exact path allowlist entry in MCP_GATEWAY_DOCKER_BIND_ALLOW_WRITABLE_PATHS.

Network egress is not globally denied by default. Servers can request disableNetwork, allowHosts, and the gateway can run with --block-network to enforce more restrictive network access. A server making network calls within the granted network configuration is not, by itself, a gateway vulnerability.

Secrets and logs

Secrets are scoped to the server that declares them. Secret names are validated before they are used with the credential resolver, and one server should not be able to receive another server's declared secrets by guessing names or using pattern metacharacters.

--block-secrets is enabled by default and scans tool-call arguments and text responses for secret-like values before and after tool execution. --log-calls is also enabled by default, but call logs record the tool name and argument shape metadata only. Raw tool-call argument keys and values must not be logged by the default call logger.

MCP routing and policy

The gateway rejects exposed tool names that collide with reserved gateway tools or with tools from another enabled server. It also rejects collisions for prompt names, resource URIs, and resource template URI templates. Dynamic registration and reload paths must apply the same collision checks before capabilities become available to clients.

Gateway policy decisions must apply consistently across direct tool calls, dynamic tool execution, mcp-exec, and code-mode generated tools. A path that invokes a denied or disabled backend tool despite policy is in scope.

In-scope report examples

  • An untrusted catalog, profile, image label, registry entry, or remote URL causes the gateway to read a host file outside the trusted catalog directory.
  • A server receives another server's secret, or a secret is sent to a remote server without being declared for that server.
  • A catalog-controlled volume mounts a sensitive host path, creates a writable host bind without an explicit writable allowlist entry, or smuggles Docker flags through mount values.
  • A default remote URL or redirect reaches loopback, private networks, cloud metadata endpoints, or other non-public destinations without the insecure URL opt-out.
  • An unauthenticated request reaches MCP protocol endpoints on the sse or streaming transports without --allow-unauthenticated.
  • A browser request with a non-localhost Origin can use MCP protocol endpoints.
  • A Docker MCP mcp/ image bypasses default signature verification or mutable tag rejection while verification is enabled.
  • A colliding tool, prompt, resource, or resource template shadows another server or a gateway capability.
  • Code-mode, dynamic tools, or mcp-exec can invoke a tool that policy denies.
  • Default call logging records raw tool-call argument keys or values.

Out-of-scope report examples

  • A user or operator explicitly enables unsafe behavior, such as --allow-unauthenticated, --verify-signatures=false, DOCKER_MCP_ALLOW_INSECURE_REMOTE_URLS=1, broad bind-mount allowlists, writable bind allowlists, custom interceptors, or intentionally granted secrets, and the reported behavior stays within that grant.
  • A malicious enabled MCP server abuses access that was intentionally granted to it, such as reading a mounted directory, using an assigned secret, contacting an allowed host, or returning malicious content to the MCP client.
  • Prompt injection, tool-description poisoning, or malicious content from a tool, README, remote service, or upstream API, unless it bypasses a gateway boundary described in this document.
  • Compromise of the local OS user, Docker daemon, Docker Desktop, host keychain, Docker credential helper, or local gateway binary.
  • Unauthenticated access to /health, or requests without an Origin header from non-browser clients.
  • Use of unsigned or malicious third-party images outside Docker MCP's signing namespace when the user or operator chose to run those images.
  • Resource consumption that remains within the configured CPU and memory limits.
  • Logs that include only tool names and argument shape metadata, without raw argument keys or values.