Docker Desktop 4.27.1 updates the builder as well as the runtime
Desktop 4.27.1 packages the container security fixes, including a classic builder cache defect that affects scratch images and API-driven builds.
A Dockerfile can describe the intended image correctly while a builder reuses a result that does not belong to it. The classic builder vulnerability disclosed with this week's container security updates makes that distinction concrete. A specially constructed image can become a cache candidate for another Dockerfile, and changes to some instructions fail to invalidate cached results. The error concerns how the builder establishes equivalence between an instruction and an existing image.
Docker Desktop 4.27.1, released today, packages Engine 25.0.2 and runc 1.1.12. Its security coverage includes the BuildKit fixes coordinated with the runc container escape disclosure. This gives Desktop users a packaged response to several defects with different causes, rather than one setting that repairs every affected operation.
Docker's build cache is central to why I find the tool useful. Instruction ordering and input selection determine how much work a rebuild can reuse. A cache that accepts the wrong result changes the correctness of the produced artifact, so its matching rules deserve the same attention as the commands in the Dockerfile.
Scratch images expose a cache identity problem
The Moby advisory for CVE-2024-24557 describes cache poisoning when the classic builder processes an image built FROM scratch. An attacker who knows the target Dockerfile can prepare an image that the builder considers a valid cached result for some steps, despite that image having come from a different Dockerfile.
The advisory's example uses a scratch base followed by a metadata instruction. Its importance is the acceptance of a result with the wrong origin. A build can proceed without executing the instruction that the reader expects to establish the next state, because the builder believes it already has that state.
This is relevant to my preference for a final image containing one static Go binary. Starting with scratch keeps that final filesystem small, but the builder still has to establish that each reused result corresponds to the requested build. The absence of application packages does not make cache identity irrelevant.
There is a second failure in the same advisory. Changes to instructions including HEALTHCHECK and ONBUILD do not cause the expected cache miss. Those instructions can affect an image's behavior without representing a conventional application file change. Reusing an old result therefore has consequences beyond whether the filesystem contains the latest executable.
The advisory specifically gives substitution of a different health check as an example. That makes the defect understandable without assuming an entire attacker-controlled application image replaces the result. Metadata used to describe or trigger behavior is part of what a correct build must preserve.
Pulling an image can affect a later build
The attack requires the builder to encounter a crafted image. Moby's advisory mentions both shared CI caches and an ordinary user pulling an image through a misspelled name or typosquatting. Those examples explain why the threat is not limited to accepting a malicious Dockerfile.
The target Dockerfile may belong to the developer. The untrusted input can instead be an image that enters the cache considered during a subsequent build. Knowledge of the target instructions helps the attacker prepare a candidate that passes the vulnerable matching logic. Image acquisition and image construction consequently share a security dependency through the cache.
This differs from the runc attack that requires a malicious working-directory reference in an image or an altered path inside a running container. The cache-poisoning problem concerns which existing build result the engine accepts. Replacing the runtime alone would leave the builder's decision unchanged.
For a repeatable build, a cached result needs to mean the same thing as the work it replaces. The advisory shows how incorrect matching breaks that expectation even when the build completes normally. A successful command exit cannot establish that the intended instructions supplied the result.
CLI defaults do not establish API behavior
Moby's impact statement distinguishes users of Engine 23.0 and later from older installations. On those newer releases, the classic builder remains relevant when a user explicitly disables BuildKit or invokes a build API that defaults to the classic implementation. The advisory names both the /build endpoint and the Go client's ImageBuild function.
This distinction matters for automation. A developer's interactive build can use BuildKit while a program speaking to the same engine takes another route. Inferring a program's builder from the default behavior of a different client can therefore misidentify its exposure.
The documented workarounds include disabling cache reuse or selecting BuildKit. For a CLI invocation, the advisory names these forms:
docker build --no-cache .
DOCKER_BUILDKIT=1 docker build .
Each line addresses the classic builder cache issue in a different way. The first avoids reuse for that build. Selecting BuildKit with the second assumes the required buildx plugin is installed. The advisory also names NoCache and the BuildKit builder version in the Go client's build options for callers using that interface.
These options change the build request, so their relevance follows the client that sends it. Setting an environment variable in an interactive shell does not establish what a separate program places in its API request. For that program, the explicit build options named by the advisory describe the intended workaround at the actual call site.
Selecting BuildKit is only a workaround for this particular vulnerability. BuildKit has its own fixes in this coordinated update, so switching to an affected BuildKit installation would not resolve the entire group. Engine 25.0.2 packages BuildKit 0.12.5, as recorded in the Engine release's packaging changes.
Build execution has several permission checks
The BuildKit advisories describe operations that occur while creating images. Parallel steps sharing cache mounts with subpaths can race and expose host files. Mountpoint cleanup can delete a host file outside the container. An interactive container API can request elevated privileges without enforcing the normal entitlement agreement.
These failures occur in different parts of execution. The cache-mount advisory concerns shared state used by parallel build steps. Its description does not imply that all ordinary cache use exposes host files. It identifies a malicious construction involving subpaths and concurrent operations.
The mountpoint-cleanup advisory concerns empty files created for mounts. A malicious Dockerfile or frontend can cause the removal operation to target a host file. That makes cleanup a separate privileged action whose target must remain within the intended filesystem.
The interactive API advisory describes missing entitlement validation. Ordinarily, elevated execution through security.insecure requires permission in the builder daemon configuration and approval by the user initiating the build. An alternative API must apply that same permission check when it requests equivalent execution.
BuildKit 0.12.5 addresses those defects. Docker's coordinated security advisory also includes CVE-2024-23650, a request that can panic the BuildKit daemon. Availability and isolation have different failure modes here, even though one packaged upgrade delivers the fixes.
Runtime replacement completes a different part of the update
Runc 1.1.12 repairs CVE-2024-21626. The runtime advisory explains how an internal descriptor can let process setup choose a working directory outside the container filesystem. Variants can also reach and overwrite host executables. These attacks involve references retained by the runtime while constructing the new process.
Its patch checks the final working directory and closes internal descriptors before executing the container binary. Other changes address the known leaks and mark descriptors close-on-exec. These measures constrain the runtime's startup state, which is a different responsibility from determining whether a build cache entry matches a requested instruction.
Desktop's release also updates containerd to 1.6.28. The release notes group that component update with Engine and runc, giving the reader specific versions for the packaged runtime stack. They additionally record a Mac fix for Desktop hanging while applying an update. That repair concerns delivery of updates, while the security entries describe what the delivered components change.
The practical consequence is that the installed Desktop application supplies fixes to machinery outside the application image. Rebuilding a minimal final stage does not replace the engine's cache matcher or the runtime used to start containers. For builds submitted to another machine, the builder performing that work has its own installed components. The local application's version identifies the local package, while the execution location determines which builder and runtime actually process the request.