Jul 6, 2026·7 min read·25 visits
Unrestricted PackBits decompression in golang.org/x/image/tiff allows unauthenticated remote attackers to trigger denial of service via memory exhaustion using a crafted 2MB TIFF image that decompresses to 745MB.
CVE-2026-46599 (also identified by Go vulnerability alias GO-2026-5032) is a high-severity denial-of-service vulnerability in the Go image repository, specifically within the TIFF decoder's PackBits decompression engine. A lack of resource limits during the parsing of Run-Length Encoded PackBits streams allows an attacker to construct a crafted TIFF image that achieves significant decompression amplification. This flaw enables an unauthenticated remote attacker to exhaust system resources, leading to an Out-of-Memory crash or a prolonged application hang.
The golang.org/x/image/tiff package provides an official decoder for Tagged Image File Format (TIFF) files in the Go programming language ecosystem. Because image decoding is a resource-intensive operation, processing untrusted file inputs exposes applications to potential resource exhaustion attacks. When applications ingest user-provided images to generate thumbnails, store avatars, or perform format conversion, they rely on the decoding library to safely restrict resource consumption.
This vulnerability, designated as CVE-2026-46599, resides specifically in the implementation of the PackBits decompression scheme inside the TIFF decoder. PackBits is a byte-oriented Run-Length Encoding (RLE) standard used to compress image data strips within a TIFF container. The vulnerability falls under the CWE-770 classification (Allocation of Resources Without Limits or Throttling), indicating that the software allocates system memory on behalf of an untrusted source without enforcing an upper bound.
Unlike more complex compression algorithms in the same package that route inputs through safe buffers with size limitations, the PackBits decoder directly processed data blocks without measuring or constraining the output size. The resulting impact is high-severity denial-of-service (DoS) via complete exhaustion of available system memory. Unauthenticated remote attackers can exploit this flaw by delivering a maliciously structured TIFF file to any Go application that decodes TIFF images.
PackBits operates on a simple state machine where each compression run begins with a signed 8-bit header byte, followed by literal or replicated data bytes. A header byte n between 0 and 127 indicates a literal run, meaning the decoder must copy the next n + 1 bytes directly to the destination. A header byte n between -127 and -1 indicates a replicated run, instructing the decoder to duplicate the single subsequent byte -n + 1 times. The value -128 is a no-op.
A replicated run can compress up to 128 bytes of repeated data into just 2 bytes of input (the header byte and the repeated byte). This structure provides a maximum single-run compression ratio of 64x. By chaining multiple replicated runs across multiple strips of a single TIFF file, an attacker can construct a high-ratio compression bomb that requires minimal input data but produces a disproportionate volume of output bytes.
The root cause of this vulnerability lies in the path routing of the main Decode function in tiff/reader.go. While other decompression algorithms such as LZW, Deflate, and CCITT restrict buffer expansion by employing the readBuf utility, the PackBits parser called unpackBits directly with a raw reader. Inside unpackBits in tiff/compress.go, the decompression loop repeatedly appended data to a destination byte slice until the input reader returned io.EOF, neglecting to verify whether the accumulated size of the buffer had exceeded the maximum safe limit configured for a single image strip.
To understand the implementation flaw, we can analyze the vulnerable code path compared to the corrected logic in the official patch. In the unpatched version of unpackBits, the function signature only accepted an io.Reader and returned the raw decompressed byte slice.
// Unpatched version of unpackBits
func unpackBits(r io.Reader) ([]byte, error) {
buf := make([]byte, 128)
dst := make([]byte, 0, 1024)
br, ok := r.(byteReader)
// ... decoding loop reads codes and appends to dst ...
for {
// ... read headers and copy
if code >= 0 {
dst = append(dst, buf[:code+1]...)
} else if code != -128 {
dst = append(dst, buf[:1-code]...)
}
}
}The patch (commit fe8ae458fe5e09e39a635719a8c2ec5393d0e815) mitigates this behavior by adding an explicit upper bound limit (lim int64) to the unpackBits parameter list. During each iteration of the decoding loop, the routine evaluates the length of the destination slice against this threshold.
// Patched version of unpackBits
func unpackBits(r io.Reader, lim int64) ([]byte, error) {
buf := make([]byte, 128)
dst := make([]byte, 0, 1024)
// ... parsing loop
for {
// ... decode literal or replicated runs
if code >= 0 {
dst = append(dst, buf[:code+1]...)
} else if code != -128 {
dst = append(dst, buf[:1-code]...)
}
// Explicit size validation added to prevent memory exhaustion
if int64(len(dst)) > lim {
return nil, FormatError("PackBits: decompressed data too large")
}
}
}Additionally, the calling site in tiff/reader.go was updated to pass blockMaxDataSize as the limit argument. This aligns the PackBits decompression path with the limits previously established for other image compression formats under CVE-2023-29408, ensuring consistent protection across all codecs.
Exploiting this vulnerability does not require any specific target configuration, prior authentication, or complex cryptographic operations. The attack vector is entirely remote and requires only that the target application exposes an endpoint accepting TIFF images for processing.
An attacker begins by creating a TIFF file containing a single large strip compressed with PackBits. The payload consists of repetitive byte sequences that map directly to high-amplification replicated runs (such as repeated headers of 0x81 followed by a null byte). A crafted payload of 2MB can easily expand to 745MB of memory upon decompression. This translates to an amplification factor of over 370x.
When the application receives the file, it calls tiff.Decode(). The library parses the TIFF tags, identifies the PackBits compression scheme (tag value 32773), and hands the file descriptor to the vulnerable unpackBits function. As the engine loops through the compressed runs, it continuously expands the buffer. This triggers excessive physical memory consumption within milliseconds, exhausting available memory, triggering garbage collection thrashing, and forcing the operating system to issue a SIGKILL signal to terminate the application.
The primary security impact of CVE-2026-46599 is a complete denial of service. Because image parsing is often executed synchronously in response to HTTP requests, a single request containing a malicious payload can crash the backend server, terminating all active sessions and transactions processed by that instance.
If the application is configured to automatically restart upon failure, an attacker can repeatedly send the malicious payload to keep the server in a continuous loop of crashing and restarting. This permanently denies access to legitimate users. In cloud environments where container orchestrators automatically spin up new instances, this attack can rapidly inflate hosting costs by driving CPU usage and memory resource limits to their maximum thresholds.
The CVSS v3.1 score for this vulnerability is 7.5 (High), reflecting a network-based, low-complexity vector with high availability impact. No confidentiality or integrity impact is present, as the vulnerability does not allow memory disclosure or arbitrary code execution.
The definitive resolution for CVE-2026-46599 is to update the Go subrepository dependency to a secure release. Developers should upgrade the golang.org/x/image package to version v0.41.0 or higher.
To apply the update, run the following commands in the directory containing the go.mod file of your project:
go get golang.org/x/image@v0.41.0
go mod tidyAfter updating the dependency, you must rebuild and redeploy all application binaries. Because Go compiles dependencies statically into the final executable, simply updating the libraries on the server host without recompiling the application will not apply the security patch.
For systems where immediate updating is not feasible, temporary workarounds can mitigate the risk. Implement a middleware layer that inspects the request body size and blocks files with .tiff or .tif extensions. Alternatively, parse the file headers to verify the magic bytes (0x49492A00 or 0x4D4D002A) and reject all TIFF payloads at the application boundary prior to invoking any image decoding functions.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
golang.org/x/image/tiff Go | < v0.41.0 | v0.41.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-770 (Allocation of Resources Without Limits or Throttling) |
| Attack Vector | Network (AV:N) |
| CVSS Score | 7.5 (High) |
| EPSS Score | 0.00353 |
| EPSS Percentile | 27.35% |
| Exploit Status | No public functional exploit code (None/PoC-only) |
| KEV Status | Not in CISA's Known Exploited Vulnerabilities (KEV) catalog |
The software allocates a resource (memory buffer) on behalf of an untrusted actor without a cap or restriction on the size of the allocation.
A property shadowing vulnerability exists in protobufjs where schema-derived names can collide with and overwrite runtime-critical internal helper properties. This issue leads to uncaught runtime exceptions and crash-based Denial of Service.
An integer truncation vulnerability (CWE-197) exists in SQLite before version 3.50.2 during the processing of aggregate queries with more than 32,767 distinct column references. This causes an internal 32-bit counter to truncate to a signed 16-bit integer, producing negative values that cause out-of-bounds heap operations in release builds.
An integer overflow vulnerability in the Windows kernel-mode HTTP driver (HTTP.sys) allows an unauthenticated remote attacker to execute arbitrary code with kernel privileges or cause a Denial of Service via a specially crafted sequence of HTTP request headers.
A memory corruption vulnerability exists in the FTS5 (Full-Text Search 5) extension of SQLite prior to version 3.53.2. An attacker can construct a malicious database file containing corrupt FTS5 page data. Querying this database triggers out-of-bounds reads and heap-based buffer overflows, potentially causing a crash or arbitrary code execution.
A mass assignment vulnerability (CWE-915) in n8n's self-service settings API endpoint (PATCH /me/settings) allows authenticated Single Sign-On (SSO) users to disable SSO enforcement for their accounts by injecting administrative parameters. This bypasses organizational identity provider controls and multi-factor authentication (MFA).
CVE-2026-55699 (also identified as GHSA-4gxm-v5v7-fqc4) is a critical path traversal and arbitrary directory deletion vulnerability in the pnpm package manager. The issue exists because the manifest validation process fails to prevent relative path segments within the package 'bin' keys. When a malicious package containing structured path traversal markers is globally installed and later manipulated, pnpm resolves the target paths through path.join() and passes the resolved paths to a recursive deletion function, resulting in arbitrary directory removal.