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
sseorstreamingtransports without--allow-unauthenticated. - A browser request with a non-localhost
Origincan 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-execcan 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 anOriginheader 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.