Aug 20, 2026·7 min read·1 visit
moby/buildkit prior to version 0.31.1 does not enforce size limits or validate file types when reading user and group databases inside build contexts, enabling attackers to crash the buildkitd daemon via memory exhaustion (OOM) or hang execution threads.
moby/buildkit is susceptible to a denial-of-service vulnerability prior to version 0.31.1. When BuildKit processes user or group directives from untrusted build contexts or base images, it reads configuration databases such as /etc/passwd and /etc/group directly into memory without enforcing boundaries. An attacker can exploit this behavior by engineering malicious files that trigger host memory exhaustion or block daemon threads indefinitely.
BuildKit is the primary backend compilation engine for modern container ecosystems, translating declarative source files (such as Dockerfiles) into Low-Level Builder (LLB) Directed Acyclic Graphs (DAGs). This execution framework operates as a high-performance daemon (buildkitd) coordinating with various frontend interfaces. During intermediate compilation stages, BuildKit frequently switches process context ownership or checks system permissions. This requires translating symbolic user and group identifiers defined in instructions like USER, COPY --chown, or RUN --mount=type=bind into numeric execution parameters.
To perform translation without executing full operating system commands inside the target runtime environment, BuildKit parses the target container's localized database files, specifically /etc/passwd and /etc/group. These files reside inside the root filesystem (rootfs) configuration path of the target image state. The attack surface exists because these files are inherently user-controlled, extracted from base images that may be obtained from untrusted or public container registries.
The vulnerability is classified under CWE-770 (Allocation of Resources Without Limits or Throttling). It represents a critical architectural gap where unvalidated, external inputs directly dictate the magnitude of resource allocations within the privileged host service environment.
The vulnerability lies within the identity resolution code paths located in executor/oci/user.go and solver/llbsolver/ops/user_linux.go. When processing instructions requiring user or group translation, the daemon resolves the target file path via fs.RootPath(root, p) to guarantee that path resolution remains jailed within the container's virtual root directory. It then attempts to open the file descriptor using a standard os.Open call.
In vulnerable versions, the application immediately reads and processes the entire contents of these files into heap memory. This open-and-read sequence lacked any size constraints or metadata validation. If the target file size is expanded to several gigabytes, the Go runtime allocates dynamic slice buffers to hold the read contents. Because the Go runtime heap allocator increases buffer capacities exponentially when growing slices, memory consumption quickly balloons, triggering the Linux host's Out-Of-Memory (OOM) killer to terminate the parent buildkitd daemon.
In addition to memory exhaustion, the original implementation failed to inspect the file mode mask returned by the file status system call. If an attacker configured /etc/passwd or /etc/group as a named pipe (FIFO) or a blocking character device, the Go synchronous file read call blocked indefinitely waiting for data. This behavior effectively starves the internal worker pool of active threads, resulting in a thread-leak denial-of-service condition where the build process hangs without recovering.
An analysis of the fix implemented across the vulnerable modules highlights how the boundary enforcement was engineered. The patch introduces a rigid upper boundary (maxUserFileBytes = 10 << 20, or 10 MiB) and adds explicit verification of the file mode using f.Stat().
Below is the technical diff showing the integration of the size constraints and type validation within executor/oci/user.go:
// Patched implementation in executor/oci/user.go
const maxUserFileBytes = 10 << 20
func openUserFile(root, p string) (io.ReadCloser, error) {
p, err := fs.RootPath(root, p)
if err != nil {
return nil, errors.WithStack(err)
}
f, err := os.Open(p)
if err != nil {
return nil, errors.WithStack(err)
}
// Verify file properties prior to allocating parsing buffers
info, err := f.Stat()
if err != nil {
f.Close()
return nil, errors.WithStack(err)
}
if !info.Mode().IsRegular() {
f.Close()
return nil, errors.Errorf("%s is not a regular file", p)
}
// Restrict stream consumer read capacities
return &limitedReadCloser{
ReadCloser: f,
r: &io.LimitedReader{R: f, N: maxUserFileBytes + 1},
name: p,
}, nil
}The wrapper structure limitedReadCloser implements the custom read control. If the underlying io.LimitedReader counts down to zero, meaning the file size exceeds the 10 MiB threshold, the routine immediately returns an error, halting further parsing and releasing the associated memory allocations.
type limitedReadCloser struct {
io.ReadCloser
r *io.LimitedReader
name string
}
func (l *limitedReadCloser) Read(p []byte) (int, error) {
n, err := l.r.Read(p)
if l.r.N == 0 {
return n, errors.Errorf("%q exceeds %d bytes", l.name, maxUserFileBytes)
}
return n, err
}This defensive design is highly effective. The use of fs.RootPath prevents symlink-based container breakouts, and the combination of IsRegular() checks and io.LimitedReader prevents resource exhaustion.
To exploit this vulnerability, an attacker must introduce a malformed base image or a malicious local directory context into the BuildKit pipeline. This is typically achieved in environments that allow arbitrary Dockerfile execution, such as multi-tenant CI/CD platforms.
To construct a memory-exhaustion payload, an attacker can create a sparse file of 15 Gigabytes directly within the /etc/passwd path of a custom base image. Because sparse files do not consume significant storage when compressed, they can easily be pushed to registries like Docker Hub. When BuildKit attempts to read the file, the uncompressed data expands fully in RAM, crashing the host daemon.
Alternatively, to trigger a thread-exhaustion hang, the attacker can replace the /etc/passwd file in their image with a named pipe (FIFO) created via mkfifo rootfs/etc/passwd. When BuildKit initiates a build and encounters a USER directive, it calls os.Open on the named pipe and blocks, consuming system resources until the thread limit is reached.
The overall impact of CVE-2026-61712 is categorized as Low by the CVSS system (Base Score 2.3), reflecting specific limitations on attack vector requirements. Specifically, the vulnerability requires user interaction because an operator or pipeline runner must initiate a container build using the malicious Dockerfile or base image.
However, in enterprise environments, the operational impact of a BuildKit crash can be severe. In shared or multi-tenant CI/CD platforms (such as Kubernetes-based runners using Tekton, Argo Workflows, or GitLab CI), a single malicious build step can terminate the shared buildkitd instance. This termination immediately disrupts all other parallel builds running on the same host, resulting in pipeline failures and cache corruption.
Since no unauthorized file write or data access occurs, Confidentiality and Integrity are unaffected. The primary impact is localized availability degradation, which can be mitigated if automatic process managers (like systemd) restart the daemon immediately, though concurrent active builds must still be rescheduled and restarted from scratch.
The permanent fix for this vulnerability is to upgrade BuildKit to version 0.31.1 or later. If immediate upgrades are not feasible, administrators can apply several configuration mitigations to reduce the risk of exploitation:
buildkitd process under systemd slice configurations or cgroup directives that enforce physical memory limitations (e.g., MemoryMax=4G). This isolates memory exhaustion crashes and prevents host-level instability.[Service]
Restart=always
RestartSec=5sbuildkitd in rootless mode limits its access to host resources and adds layer of isolation between the build runner and the host operating system.CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
buildkit moby | < 0.31.1 | 0.31.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-770 |
| Attack Vector | Network |
| CVSS v4.0 | 2.3 (Low) |
| Impact | Denial of Service (DoS) |
| Exploit Status | none |
| CISA KEV Status | No |
The software allocates memory or other system resources on behalf of an untrusted actor without placing an upper bound on the amount of resources that can be requested, leading to exhaustion of host resources.
A detailed technical analysis of CVE-2026-61711, an input validation flaw in Moby BuildKit prior to version 0.31.1. The flaw allows unauthorized or custom frontends to construct build execution environments where Seccomp and AppArmor configurations are completely disabled by supplying an invalid protobuf enum index, resulting in an elevated kernel-level attack surface inside the build sandbox.
CVE-2026-59992 is a critical broken access control vulnerability in the first-party production media adapters of Tina CMS, including next-tinacms-s3, next-tinacms-dos, next-tinacms-azure, and next-tinacms-cloudinary. The issue allows authenticated editors to escape the configured mediaRoot directory containment, facilitating unauthorized file uploads, modifications, and deletions across the entire storage bucket or container.
A Cross-Site Request Forgery (CSRF) vulnerability in the local development server of @tinacms/cli allowed malicious cross-origin pages to send state-changing HTTP requests. This issue permitted attackers to write arbitrary files into a developer's project directory or manipulate search and GraphQL indices without authorization.
A high-severity path traversal vulnerability exists in the @logto/tunnel npm package (part of the Logto repository) prior to version 0.3.9. Remote unauthenticated attackers can exploit this vulnerability to read arbitrary local files by sending crafted HTTP requests with directory traversal sequences when the static file proxy is active.
A critical stored Cross-Site Scripting (XSS) vulnerability was identified in Froxlor server administration software panel before version 2.3.8. Authenticated customers with DNS editor privileges can inject malicious JavaScript into DNS TXT records. Because the application processes these values via a raw formatting callback without context-aware HTML entity encoding, the payload executes in the security context of administrative users who view the affected domain's DNS zones.
An authenticated administrator with privileges to manage admin accounts (such as change_serversettings) can execute arbitrary SQL commands via a second-order SQL injection vulnerability. The flaw resides in Froxlor's administrative API endpoints, specifically during the handling of IP address mapping parameters which are stored as serialized arrays and later interpolated without sanitization into active database queries. This vulnerability allows high-privileged administrative attackers to compromise the database. By injecting a payload into administrative profile metadata, an attacker can extract sensitive credentials, manipulate backend settings, or potentially disrupt database integrity. The vulnerability affects all versions of Froxlor prior to 2.3.8.