See how docker compares to other vendors in security performance
Summary
A security vulnerability has been detected that allows plugins privilege validation to be bypassed during docker plugin install. Due to an error in the daemon's privilege comparison logic, the daemon may incorrectly accept a privilege set that differs from the one approved by the user.
Plugins that request exactly one privilege are also affected, because no comparison is performed at all.
Impact
If plugins are not in use, there is no impact.
When a plugin is installed, the daemon computes the privileges required by the plugin's configuration and compares them with the privileges approved during installation. A malicious plugin can exploit this bug so that the daemon accepts privileges that differ from what was intended to be approved.
Anyone who depends on the plugin installation approval flow as a meaningful security boundary is potentially impacted.
Depending on the privilege set involved, this may include highly sensitive plugin permissions such as broad device access.
For consideration: exploitation still requires a plugin to be installed from a malicious source, and Docker plugins are relatively uncommon. Docker Desktop also does not support plugins.
Workarounds
If unable to update immediately: - Do not install plugins from untrusted sources - Carefully review all privileges requested during docker plugin install - Restrict access to the Docker daemon to trusted parties, following the principle of least privilege - Avoid relying on plugin privilege approval as the only control boundary for sensitive environments
Credits
- Reported by Cody (c@wormhole.guru, PGP 0x9FA5B73E)
Summary
A race condition during docker cp mount setup allows a malicious container to redirect a bind mount target to an arbitrary host path, potentially overwriting host files or causing denial of service.
Details
When copying files into a container, the daemon sets up a temporary filesystem view by bind-mounting volumes into a private mount namespace. During this setup, the mount destination is created inside the container root and then a bind mount is attached using the container-relative path resolved to an absolute host path.
Between mountpoint creation and the mount() syscall, a process running inside the container can replace the destination (or a parent path component) with a symlink pointing to an arbitrary location on the host. The mount() syscall follows the symlink, causing the volume to be bind-mounted onto an arbitrary host path instead of the intended container path.
Impact
A malicious container can redirect a volume bind mount to an arbitrary host path. The impact depends on the volume content and mount options:
- If the volume is writable, arbitrary host files at the redirected path could be overwritten with the volume's contents. - If the volume is read-only, the host path is masked by the mount for the duration of the operation, causing denial of service. - In all cases the mount is temporary (torn down after the docker cp completes), but the effects of any writes persist.
Conditions for exploitation
- A container must have at least one volume mount. - A process inside the container must be able to rapidly create and swap symlinks at the volume mount destination path. - An operator must initiate a docker cp into that container, or call the PUT /containers/{id}/archive or HEAD /containers/{id}/archive API endpoints.
Not affected
- Containers that do not have volume mounts are not affected, as the race occurs during volume bind-mount setup.
Workarounds
- Only run containers from trusted images. - Avoid using docker cp with untrusted running containers. - Use authorization plugins to restrict access to the archive API endpoints (PUT /containers/{id}/archive, HEAD /containers/{id}/archive).
Moby is an open source container framework. In versions prior to 29.5.1 and in moby/moby v2 prior to v2.0.0-beta.14, when a compressed archive is uploaded to a container via PUT /containers/{id}/archive or piped through docker cp -, the daemon resolves decompression binaries (such as xz or unpigz) from the container's filesystem rather than the host's due to incorrect ordering of operations. A malicious container image containing a trojanized decompression binary can achieve arbitrary code execution with full daemon privileges, including host root UID and unrestricted capabilities, when a user uploads a compressed (xz or gzip) archive into that container. This issue is fixed in Docker Engine 29.5.1 and moby/moby v2.0.0-beta.14. Workarounds include only running containers from trusted images, using authorization plugins to restrict access to the PUT /containers/{id}/archive endpoint, and avoiding piping compressed archives into containers created from untrusted images
Moby is an open source container framework. In Docker Engine prior to version 29.5.1, Docker Daemon versions 28.5.2 and prior, and Moby Daemon prior to version 2.0.0-beta.14, a race condition during docker cp mount setup allows a malicious container to redirect a bind mount target to an arbitrary host path, potentially overwriting host files or causing denial of service. This issue has been patched in Docker Engine version 29.5.1 and Moby Daemon version 2.0.0-beta.14.
Docker Sandboxes (sbx) enforces an HTTP/S-only egress allowlist but does not apply it to DNS resolution: the per-network embedded DNS server forwards any queried name to the host resolver whenever the network is internet-connected, without consulting the policy. A workload inside a sandbox, which the threat model treats as untrusted, can therefore encode data into DNS labels for an attacker-controlled domain and exfiltrate it through a DNS covert channel, bypassing the configured allowlist.
Docker Sandboxes (sbx) blocks ICMP egress with an authorizer applied only at network-creation time, and does not re-apply it to networks rebuilt from disk when the Docker daemon restarts, so a restart-surviving sandbox forwards ICMP to arbitrary hosts. A workload inside a sandbox, which the threat model treats as untrusted, can therefore defeat the documented ICMP egress block to perform network reconnaissance and exfiltrate data over an ICMP covert channel, regardless of the configured allowlist.
Impact Some cache backends allow configuring their credentials by setting secrets directly as attribute values in cache-to/cache-from configuration. If this was done by the user, these secure values could be captured together with OpenTelemetry trace as part of the arguments and flags for the traced CLI command. Passing tokens to Github cache backend via environment variables or using registry authentication is not affected.
If you passed a token value like this and use a custom OpenTelemetry collector for computing traces you should make sure that your traces are kept secure. OpenTelemetry traces are also saved in BuildKit daemon's history records.
Patches Issue has been fixed in Buildx v0.21.3 or newer.
Workarounds Avoid passing cache backend credentials with CLI arguments. Make sure access to traces and BuildKit history records is kept secure.
Author here. We discovered a vulnerability in docker cp that allows a malicious container to create or overwrite files on the machine running the Docker CLI.
The exploit combines a filesystem race in Docker’s archive creation with unsafe symlink handling during extraction. Depending on the CLI user’s privileges, this can lead to developer-account compromise or root code execution. Docker confirmed that sbx cp was also affected.
Fixed versions:
Docker Engine/CLI 29.7.2+ Docker Desktop 4.86.0+ Docker Sandboxes 0.38.0+
Happy to answer technical questions.
https://www.imperva.com/blog/copyescape-taking-over-docker-hosts-with-docker-cp/ Author here. I discovered a vulnerability in docker cp that allows a malicious container to create or overwrite files on the machine running the Docker CLI.
The exploit combines a filesystem race in Docker’s archive creation with unsafe symlink handling during extraction. Depending on the CLI user’s privileges, this can lead to code execution. Docker confirmed that sbx cp was also affected.
Fixed versions:
Docker Engine/CLI 29.7.2+ Docker Desktop 4.86.0+ Docker Sandboxes 0.38.0+
Happy to answer technical questions.
BuildKit's cache mount source= selector on Windows Container on Windows (WCOW) workers does not detect NTFS directory junctions placed inside the cache root. A build authored by an untrusted user on a WCOW-configured BuildKit daemon can read arbitrary host files reachable to the BuildKit daemon process.
A crafted message in the BuildKit low-level build API can be used to remove the contents of the /tmp directory. The action that can normally be used to delete files inside the build container rootfs can escape into the real host temp directory.
BuildKit custom frontends or clients using the raw low-level API can set git.checkoutbundle=true when checking out Git sources. If the Git source is malicious, this could lead to a crafted command invocation on the host.
The Docker CLI --use-api-socket flag bypasses Enhanced Container Isolation (ECI) restrictions in Docker Desktop. When ECI is enabled, Docker socket mounts from containers are denied unless explicitly allowed via the admin-settings configuration. However, the --use-api-socket flag adds the Docker socket mount via the HostConfig.Mounts field rather than the HostConfig.Binds field. The ECI enforcement in the Docker Desktop API proxy only inspected Binds, allowing the mount to pass unchecked. This grants a container full access to the Docker Engine socket and, if the host user has logged in to container registries, their authentication credentials.
A local attacker with the ability to run Docker CLI commands can exploit this to escape ECI restrictions, access the Docker Engine, and potentially escalate privileges.
The MLX inference backend in Docker Model Runner on macOS uses the MLX-LM library, which unconditionally imports and executes arbitrary Python files from model directories via the modelfile configuration field in config.json. When a model's config.json specifies a modelfile pointing to a Python file, MLX-LM uses importlib to load and execute it with no trustremotecode gate or equivalent safety check. The MLX backend runs without sandboxing, resulting in arbitrary code execution on the Docker host as the Docker Desktop user.
Any container on the Docker network can trigger this by calling the model-runner.docker.internal API to pull a malicious model from an attacker-controlled OCI registry and request inference.
The vllm-metal inference backend in Docker Model Runner on macOS unconditionally sets trustremotecode=True when loading model tokenizers, and runs without sandboxing. This causes transformers.AutoTokenizer.frompretrained() to import and execute arbitrary Python files included in any model pulled from an OCI registry, resulting in arbitrary code execution on the Docker host as the Docker Desktop user when inference is triggered.
Any container on the Docker network can trigger this by calling the model-runner.docker.internal API to pull a malicious model and request inference.
This vulnerability allows local attackers to escape the model runner sandbox on affected installations of Docker Desktop for macOS. An attacker must first obtain the ability to execute low-privileged code within the sandbox in order to exploit this vulnerability. The ZDI has assigned a CVSS rating of 8.8.
This vulnerability allows local attackers to escape the model runner sandbox on affected installations of Docker Desktop for macOS. An attacker must first obtain the ability to execute low-privileged code within the sandbox in order to exploit this vulnerability. The ZDI has assigned a CVSS rating of 8.8.
Fixed a VM panic caused by unbounded recursion in the grpcfuse kernel module when a container created deeply nested directories on a bind-mounted host folder and triggered a dentry invalidation event. This issue has been fixed in Docker Desktop 4.76.0.
Docker CLI for Windows searches for plugin binaries in C:\ProgramData\Docker\cli-plugins, a directory that does not exist by default. A low-privileged attacker can create this directory and place malicious CLI plugin binaries (docker-compose.exe, docker-buildx.exe, etc.) that are executed when a victim user opens Docker Desktop or invokes Docker CLI plugin features, and allow privilege-escalation if the docker CLI is executed as a privileged user.
This issue affects Docker CLI: through 29.1.5 and Windows binaries acting as a CLI-plugin manager using the github.com/docker/cli/cli-plugins/manager https://pkg.go.dev/github.com/docker/cli@v29.1.5+incompatible/cli-plugins/manager package, such as Docker Compose.
This issue does not impact non-Windows binaries, and projects not using the plugin-manager code.
Distribution is a toolkit to pack, ship, store, and deliver container content. Prior to 3.1.0, distribution can restore read access in repo a after an explicit delete when storage.cache.blobdescriptor: redis and storage.delete.enabled: true are both enabled. The delete path clears the shared digest descriptor but leaves stale repo-scoped membership behind, so a later Stat or Get from repo b repopulates the shared descriptor and makes the deleted blob readable from repo a again. This vulnerability is fixed in 3.1.0.
This vulnerability allows remote attackers to execute arbitrary code on affected installations of Docker MCP Plugin. User interaction is required to exploit this vulnerability in that the target must reference a malicious Docker image via a docker URI scheme. The ZDI has assigned a CVSS rating of 8.6. The following CVEs are assigned: CVE-2026-55887.
This vulnerability allows remote attackers to execute arbitrary code on affected installations of Docker MCP Plugin. User interaction is required to exploit this vulnerability in that the target must reference a malicious Docker image via a docker URI scheme. The ZDI has assigned a CVSS rating of 8.6. The following CVEs are assigned: CVE-2026-55887.
Summary
A race condition during docker cp mount setup allows a malicious container to create empty files or directories at arbitrary absolute paths on the host filesystem.
This advisory covers the race during mountpoint creation. The related race during the subsequent mount syscall is tracked in GHSA-rg2x-37c3-w2rh
Details
When copying files into a container, the daemon sets up a temporary filesystem view by bind-mounting volumes into a private mount namespace. During this setup, the mount destination path is first resolved within the container's root filesystem using GetResourcePath, and then used to create the mountpoint (file or directory) if it does not already exist via createIfNotExists.
Between path resolution and mountpoint creation, a process running inside the container can swap a path component for a symlink pointing to an arbitrary location on the host. Because createIfNotExists operates on the already-resolved absolute path using standard os.MkdirAll and os.OpenFile — which follow symlinks in intermediate path components — the symlink is followed and the file or directory is created outside the container root filesystem, as root.
Impact
A malicious container can create empty files or directories at arbitrary absolute paths on the host filesystem, running as root. This enables persistent denial of service — for example:
- Converting /etc/docker/daemon.json into a directory prevents the daemon from restarting - Creating /etc/nologin prevents user logins - Overwriting critical system paths with empty files can break host services
The container does not gain read or write access to existing host files — only the ability to create new empty files or directories at chosen paths.
Conditions for exploitation
- A container must be running with a process that can rapidly create and swap symlinks at a volume mount destination path. - An operator must initiate a docker cp into that container, or call the PUT /containers/{id}/archive or HEAD /containers/{id}/archive API endpoints.
Not affected
- Containers that do not have volume mounts are not affected, as the race occurs during volume bind-mount setup.
Patches
Mountpoint creation is now scoped to the container root using os.Root (Go 1.24+), which refuses to follow symlinks that escape the opened root directory. All filesystem operations in createIfNotExists (MkdirAll, OpenFile) are performed through the os.Root handle, so even if a symlink swap occurs after path resolution, the creation stays confined to the container root.
Workarounds
- Only run containers from trusted images. - Avoid using docker cp with untrusted running containers. - Use authorization plugins to restrict access to the archive API endpoints (PUT /containers/{id}/archive, HEAD /containers/{id}/archive).
System environment variables are recorded in Docker Desktop diagnostic logs, when using shell auto-completion. This leads to unintentional disclosure of sensitive information such as api keys, passwords, etc. A malicious actor with read access to these logs could obtain secrets and further use them to gain unauthorized access to other systems. Starting with version 4.43.0 Docker Desktop no longer logs system environment variables as part of diagnostics log collection.
In Docker Desktop before v4.29.0, an attacker who has gained access to the Docker Desktop VM through a container breakout can further escape to the host by passing extensions and dashboard related IPC messages.
Docker Desktop v4.29.0 https://docs.docker.com/desktop/release-notes/#4290 fixes the issue on MacOS, Linux and Windows with Hyper-V backend.
As exploitation requires "Allow only extensions distributed through the Docker Marketplace" to be disabled, Docker Desktop v4.31.0 https://docs.docker.com/desktop/release-notes/#4310 additionally changes the default configuration to enable this setting by default.
In Docker Desktop on Windows before v4.31.0 allows a user in the docker-users group to cause a Windows Denial-of-Service through the exec-path Docker daemon config option in Windows containers mode.
Impact
A bug was found in the Docker CLI where running docker login my-private-registry.example.com with a misconfigured configuration file (typically ~/.docker/config.json) listing a credsStore or credHelpers that could not be executed would result in any provided credentials being sent to registry-1.docker.io rather than the intended private registry.
Patches
This bug has been fixed in Docker CLI 20.10.9. Users should update to this version as soon as possible.
Workarounds
Ensure that any configured credsStore or credHelpers entries in the configuration file reference an installed credential helper that is executable and on the PATH.
For more information
If you have any questions or comments about this advisory:
Open an issue Email us at security@docker.com if you think you’ve found a security bug
Docker Desktop Community before 2.5.0.0 on macOS mishandles certificate checking, leading to local privilege escalation.
Docker Desktop before 3.6.0 suffers from incorrect access control. If a low-privileged account is able to access the server running the Windows containers, it can lead to a full container compromise in both process isolation and Hyper-V isolation modes. This security issue leads an attacker with low privilege to read, write and possibly even execute code inside the containers.
Docker Desktop Community Edition before 2.1.0.1 allows local users to gain privileges by placing a Trojan horse docker-credential-wincred.exe file in %PROGRAMDATA%\DockerDesktop\version-bin\ as a low-privilege user, and then waiting for an admin or service user to authenticate with Docker, restart Docker, or run 'docker login' to force the command.