Apr 21, 2026·7 min read·1 visit
Unbounded io.Copy operations in OpenBao's OCI plugin extraction allow decompression bombs to exhaust host disk space. The flaw was remediated in version 2.5.3 by implementing io.LimitReader and strict extraction size validations.
OpenBao versions prior to 2.5.3 are vulnerable to a resource exhaustion denial-of-service (DoS) flaw due to unbounded disk writes during OCI plugin extraction. A crafted container image served from a compromised registry acts as a decompression bomb, exhausting host disk space when OpenBao streams the data directly to disk without enforcing size limits.
OpenBao utilizes an Open Container Initiative (OCI) downloader mechanism to retrieve and extract plugins from container image registries. The affected component, residing in the helper/pluginutil/oci/downloader.go module, is responsible for processing compressed image layers and writing the plugin binaries to the local filesystem cache. This subsystem handles untrusted data streams when processing images originating from remote registries.
The vulnerability manifests as an uncontrolled resource consumption flaw (CWE-400) during the extraction phase of the plugin download lifecycle. OpenBao reads the compressed GZIP stream from the container layer and writes the decompressed payload to disk without enforcing maximum allocation thresholds. Processing a maliciously crafted, highly compressed archive results in the rapid depletion of available storage capacity on the host system.
The attack surface is contingent upon the administrative configuration of the OpenBao instance. To exploit this flaw, an adversary must possess the ability to serve a malicious container image from an OCI registry that the target OpenBao instance is configured to trust. The vulnerability triggers automatically upon the initiation of a plugin download operation, requiring no further interaction or authentication from the attacker.
The root cause of CVE-2026-39396 lies in the unsafe application of the standard library io.Copy function within the ExtractPluginFromImage() routine. The function maps a decompressed tar.Reader stream directly to a local file handle. The implementation relies entirely on the internal bounds of the source stream to determine the termination of the write operation.
In Go, the io.Copy function operates by continuously transferring bytes from the source io.Reader to the destination io.Writer until it encounters an EOF marker. When the source is a GZIP-compressed layer containing a decompression bomb, the stream yields an arbitrary volume of null bytes or repeating patterns. The function persistently writes these bytes to the disk, bypassing any memory-based constraints because the data streams directly to the file system block by block.
OpenBao implements an integrity verification mechanism by calculating the SHA256 hash of the extracted plugin binary. However, the cryptographic validation occurs strictly after the io.Copy operation completes. The system writes the entire decompressed payload to the filesystem before inspecting the hash, rendering the validation check ineffective against resource exhaustion attacks that compromise availability during the write phase.
Prior to version 2.5.3, the plugin extraction logic directly fed the unfiltered tar.Reader to the destination file. The application trusted the dimensions of the incoming stream, ignoring the discrepancy between the compressed payload size over the network and its decompressed footprint on disk. The absence of a bounding mechanism left the filesystem exposed to unbounded write operations.
The remediation introduced in commit af576af5322c6552a017ad10fd76aa4f40fd021e implements a multi-layered defense strategy. The developers introduced a configurable hard limit via plugin_download_max_size, enforcing an upper bound of 512 MiB by default. Before initiating any extraction, the system utilizes the shirou/gopsutil library to interrogate the underlying filesystem, ensuring the available disk capacity exceeds the size declared in the Tar archive header.
The core cryptographic mitigation involves restricting the reader itself using io.LimitReader. By wrapping the source stream with io.LimitReader(tarReader, header.Size+1), the standard library forcibly truncates the input if the stream yields more bytes than explicitly declared. Following the bounded read, a strict post-extraction check verifies that the total bytes written precisely matches the header declaration, failing the operation on any deviation.
// Post-patch extraction logic
if header.Size > d.maxPluginSize() { // 1. Max size configuration check
return fmt.Errorf("plugin binary size of %d MiB exceeds allowed size of %d MiB", header.Size/1024/1024, d.maxPluginSize()/1024/1024)
}
diskUsage, err := disk.Usage(filepath.Dir(targetPath))
if diskUsage.Free < uint64(header.Size) { // 2. Capacity validation
return fmt.Errorf("not enough space left on disk to download plugin")
}
// 3. Bounded streaming to prevent bomb expansion
limitReader := io.LimitReader(tarReader, header.Size+1)
n, copyErr := io.Copy(outFile, limitReader)
if n != header.Size { // 4. Strict byte count validation
err = fmt.Errorf("file size was different than reported in tar header")
}Constructing the payload requires the attacker to generate a standard zip bomb, tailored for the GZIP compression algorithm utilized by OCI containers. The adversary synthesizes a massive file consisting entirely of highly compressible sequences, such as consecutive null bytes, achieving extreme compression ratios. A payload of a few megabytes compresses down from a multi-gigabyte virtual footprint.
The delivery mechanism leverages the standard OCI distribution specification. The attacker packages the zip bomb as an independent layer within a container image and pushes the composite artifact to a target registry. The adversary must manipulate the registry routing or compromise existing credentials to ensure the OpenBao instance resolves the attacker-controlled image during a plugin fetch request.
Triggering the exploit sequence relies on the initiation of a plugin download. When an administrator or a scheduled system operation requests the malicious plugin, OpenBao retrieves the compressed layer. As the application processes the layer, the io.Copy routine unwinds the highly compressed payload, rapidly consuming inodes and storage blocks until the filesystem reaches 100% utilization.
Successful exploitation of this vulnerability results in a localized Denial of Service condition on the host system running the OpenBao instance. Exhausting the underlying disk volume prevents OpenBao from writing operational telemetry, storing audit logs, or persisting new secret configurations. Other services sharing the same storage partition will simultaneously experience critical operational failures due to the lack of writable blocks.
The CVSS v3.1 vector evaluates to CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:L with a base score of 3.1. The availability impact is categorized as low because the OpenBao application process does not inherently crash or terminate; instead, its functional capacity is severely degraded by the environmental constraints. Confidentiality and integrity metrics remain unaffected, as the vulnerability does not expose sensitive memory or allow arbitrary logic execution.
The attack complexity is elevated by the stringent prerequisite of OCI registry control. An attacker cannot simply transmit the malicious payload directly to an OpenBao listener; they must pivot through a configured registry. This architectural constraint significantly mitigates the probability of widespread automated exploitation, aligning with the low EPSS percentile score of 9.66.
The primary remediation strategy requires upgrading all OpenBao deployments to version 2.5.3 or subsequent releases. The patch introduces the necessary bounding logic and the io.LimitReader wrapper that systemically prevents the decompression stream from exceeding declared thresholds, neutralizing the zip bomb attack vector at the standard library level.
Administrators operating patched versions must proactively define the plugin_download_max_size parameter within their server configuration files. Setting this threshold to a pragmatic value ensures that even legitimately oversized, uncompressed plugins do not inadvertently monopolize system storage. Security teams must restrict OpenBao to interact exclusively with trusted, internally managed OCI registries to eliminate the untrusted payload delivery channel entirely.
Detection telemetry should focus on disk utilization metrics and specific application error signatures. Infrastructure monitoring tools must alert operators to sudden, steep accelerations in disk consumption on the volumes mounting the OpenBao .oci-cache directory. Log aggregators should parse OpenBao output streams for explicit warning strings, specifically identifying phrases such as "not enough space left on disk to download plugin" and "file size was different than reported in tar header".
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
OpenBao OpenBao | < 2.5.3 | 2.5.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-400 / CWE-770 |
| Attack Vector | Network (Via Registry) |
| CVSS Score | 3.1 (Low) |
| EPSS Score | 0.00033 |
| Impact | Denial of Service (Disk Exhaustion) |
| Exploit Status | Proof of Concept |
| KEV Status | Not Listed |
The software does not properly control the allocation and maintenance of a limited resource, thereby enabling an attacker to influence the amount of resources consumed.