CodeAnt AI Security Research
One Malformed Zip File Crashes Your Node.js Server: Denial of Service in npm's Most Downloaded Zip Library (29M+ Weekly Downloads)

Amartya Jha
CEO, CodeAnt AI
TL;DR
A single crafted zip file can crash any Node.js server that processes zip uploads. No authentication required. No user interaction. One request, one crash. The vulnerable library is yauzl, 29+ million weekly npm downloads, and the zip parsing layer behind VS Code, Electron, Puppeteer, electron-builder, and thousands of applications you use every day. The root cause? An off-by-one error in a timestamp parser introduced in v3.2.0. The fix is one character. Upgrade to v3.2.1 or later immediately.
Vulnerability at a Glance
Field | Value |
|---|---|
Package | |
Weekly Downloads | 29,139,181 |
GitHub Stars | 795 |
Affected Versions | 3.2.0 |
Fixed Version | 3.2.1 |
CVSS v3.1 Score | 5.3 MEDIUM |
CVSS Vector | AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L |
CWE | CWE-193 (Off-by-One Error), CWE-125 (Out-of-bounds Read) |
Discovered By | CodeAnt AI Code Reviewer |
Acknowledged In |
What if a zip file containing 4 extra bytes of crafted metadata could crash your Node.js server?
That’s what we found in yauzl,the most widely-used zip parsing library in the Node.js ecosystem. yauzl is the library behind extract-zip, which is used by VS Code, Electron, Puppeteer, electron-builder, and thousands of other projects. If your Node.js application handles zip files, there’s a good chance yauzl is somewhere in your dependency tree.
An off-by-one error in the NTFS timestamp extra field parser, introduced in v3.2.0, allows a malformed zip file to trigger an unhandled ERR_OUT_OF_RANGE exception. The Node.js process crashes. No graceful error. No recovery. One zip file, one crash.
The patch is now live. If you use yauzl 3.2.0, stop reading and update:
Now, here’s how we found it.
Where This Started
We’ve been systematically auditing high-impact npm packages as part of our ongoing security research program at CodeAnt AI. The methodology is simple: take the most downloaded packages, run our AI code reviewer across recent changes, and look for patterns that rule-based tools miss.
When yauzl 3.2.0 shipped with new NTFS timestamp parsing support (PR #160), our AI reviewer flagged an anomaly in index.js at line 620: a while loop condition that allowed the cursor to exceed the buffer boundary by up to 4 bytes. The AI identified the semantic mismatch — the loop was checking cursor < data.length + 4 when it should have been checking cursor + 4 <= data.length. The off-by-one meant readUInt16LE() would attempt to read past the end of the buffer.
Our security engineer verified the flag, traced the execution path, built a minimal proof of concept, and confirmed: any server that accepts zip files and calls entry.getLastModDate() on entries with a crafted NTFS extra field will crash with an unhandled exception.
The entire analysis, from AI flag to confirmed DoS — took less than one hour.
The Root Cause: An Off-by-One in a New Feature
yauzl 3.2.0 added support for reading NTFS extended timestamp fields (extra field ID 0x000a). This was a welcome improvement, NTFS timestamps offer nanosecond precision compared to the 2-second precision of DOS timestamps.
The parser iterates over attribute tags inside the NTFS extra field data:
The condition cursor < data.length + 4 allows cursor to reach values up to data.length + 3. When cursor equals data.length, the readUInt16LE(cursor) call attempts to read 2 bytes starting at an offset beyond the buffer boundary. Node.js throws ERR_OUT_OF_RANGE. The process crashes.
The Fix: One Character
That’s it. The corrected condition ensures the loop only continues when there are at least 4 bytes remaining in the buffer — enough to read both the tag and size fields without overflowing.
The fix was published as yauzl v3.2.1 with the changelog entry:
Fix crash when reading certain corrupted NTFS timestamp extra fields. Thanks to CodeAnt AI Code Reviewer.
The Proof of Concept
The vulnerability can be demonstrated directly with a minimal buffer:
We confirmed crashes for NTFS data lengths of 4, 8, and 11 bytes. Lengths of 12 or more bytes correspond to well-formed NTFS fields (which contain a 24-byte timestamp triplet) and do not crash.
The attack vector is any application that:
Accepts zip file uploads from users
Uses yauzl to parse those zip files
Calls
entry.getLastModDate()on the parsed entries
An attacker crafts a zip file with a single entry containing an NTFS extra field (0x000a) with a data payload of exactly 4, 8, or 11 bytes. When the application processes this file, the NTFS parser loop overflows, readUInt16LE() throws, and the Node.js process exits.
What the Attacker Can Do
Goal | Result |
|---|---|
Crash a file upload endpoint | Single malformed zip file → unhandled exception → process exit |
Denial of service on a CI/CD pipeline | Malicious zip in a repository → build system crashes on extraction |
Disrupt an Electron application | Crafted zip file opened in app → renderer or main process crash |
Repeated restarts | Automated uploads keep crashing the server on each restart |
This is not remote code execution. It’s a denial-of-service vulnerability. But for any production server that handles zip files — file upload services, CI/CD pipelines, document processors, Electron apps — an unhandled crash is a real availability risk.
Blast Radius: 29 Million Weekly npm Downloads
yauzl is the dominant zip parsing library in the Node.js ecosystem:
Metric | Value |
|---|---|
Weekly npm downloads | 29,139,181 |
GitHub stars | 795 |
npm dependents | 450+ packages |
GitHub dependent repositories | 5,000+ |
But the raw numbers understate the impact. yauzl sits at the bottom of a deep dependency tree. The packages that depend on yauzl are themselves depended on by thousands more.
The Dependency Chain
yauzl’s most important direct dependent is extract-zip, which is the standard zip extraction utility in the Node.js ecosystem. And extract-zip is used by:
Project | GitHub Stars | How yauzl is used |
|---|---|---|
microsoft/vscode | 170,000+ | Extension installation, update extraction |
electron/electron | 116,000+ | App packaging and distribution |
puppeteer | 89,000+ | Chromium binary download and extraction |
electron-builder | 13,000+ | Build artifact packaging |
@vscode/test-electron | — | VS Code extension test framework |
Any application built on Electron — VS Code, Slack Desktop, Discord, Figma Desktop, Notion Desktop — has yauzl somewhere in its dependency tree. Any CI/CD pipeline that extracts zip artifacts likely uses yauzl through extract-zip or a similar wrapper.
Why Traditional Tools Miss This
We tested the major security tools against this vulnerability:
Tool | Detects this vulnerability? | Why? |
|---|---|---|
CodeAnt AI | Yes ✅ | AI analysis of new code for semantic buffer safety issues |
Snyk | No ❌ | No advisory in Snyk vulnerability database |
Semgrep | No ❌ | No rule for off-by-one in buffer loop conditions |
SonarQube | No ❌ | No rule for Node.js buffer boundary validation in while loops |
ESLint | No ❌ | No security-aware buffer bounds checking |
The gap here is different from our previous CVE disclosures. This isn’t a case where the advisory hasn’t propagated yet. This is a case where the vulnerability is in new code — code that was just shipped in a feature PR, reviewed by the maintainer, and released. No rule-based tool has a pattern for “while loop condition allows buffer cursor to exceed bounds by a constant.”
Our AI code reviewer catches this because it understands what the code is doing, not just what it looks like. A loop that iterates over a buffer and reads fixed-width fields must ensure the cursor stays within bounds at every iteration. The AI recognises when the arithmetic in the loop condition doesn’t guarantee this — regardless of whether anyone has ever written a Semgrep rule for this specific pattern.
A Note on yauzl and Josh Wolfe
yauzl is one of those packages that the entire Node.js ecosystem relies on without most developers knowing it exists. It’s a library that does one thing — parse zip files — and does it with obsessive correctness. Josh Wolfe has maintained it for over a decade, with meticulous adherence to the zip file specification and careful attention to security (yauzl’s validateEntrySizes and validateFileName features are exemplary).
When we reported this vulnerability, Josh acknowledged it within days and published the fix promptly. The changelog credits our team by name. That’s the kind of professionalism that keeps the open-source ecosystem running.
We said this last week about Steve and simple-git, and the week before about Jérôme and pac4j: open-source maintainers carry the weight of the modern software supply chain. If your company depends on yauzl — and if you use Node.js, it almost certainly does — consider supporting the maintainer.
Josh, thank you.
Timeline
Date | Event |
|---|---|
February 28, 2026 | Vulnerability flagged by CodeAnt AI code reviewer; confirmed by security engineer |
March 1, 2026 | Reported to maintainer (Josh Wolfe) via email |
March 8, 2026 | Follow-up sent |
March 10, 2026 | Maintainer acknowledges the bug |
March 10, 2026 | Fix published as v3.2.1 with CodeAnt AI credited in changelog |
Are You Affected?
Step 1: Check if you depend on yauzl
If you see version 3.2.0, you are affected. Earlier versions (2.x) are not affected — the NTFS parser was introduced in 3.2.0.
Step 2: Check your exposure
You’re at risk if your application:
Accepts zip file uploads from untrusted sources
Extracts zip files in CI/CD pipelines
Calls
entry.getLastModDate()on parsed zip entriesUses
extract-zipor any wrapper that callsgetLastModDate()internally
Step 3: Update
Verify:
If you cannot upgrade immediately, wrap getLastModDate() calls in a try/catch to prevent the unhandled exception from crashing your process.
Three Vulnerabilities in 1 Weeks
We published CVE-2026-29000, a complete authentication bypass in pac4j-jwt, CVE-2026-28292,a CVSS 9.8 RCE in simple-git where changing one letter to uppercase bypasses two prior security patches. This week, an OOB read in yauzl that crashes any Node.js server processing malformed zip files.
Three different ecosystems. Three different vulnerability classes. Three different severity levels. Same research program. Same AI code reviewer.
The pattern is consistent: whether it’s a bypass of an existing security control, a flaw in new feature code, or a semantic mismatch between a regex and the system it protects — our AI finds what rule-based tools don’t. It doesn’t pattern-match against known CVEs. It reasons about whether the code actually does what it’s supposed to do.
A while loop that reads 4 bytes per iteration but checks cursor < data.length + 4 instead of cursor + 4 <= data.length is not a known vulnerability pattern. It’s a logic error. That’s what AI catches and static analysis rules don’t.
This research is part of an ongoing effort by CodeAnt AI Security Research to audit widely-used open-source packages for security vulnerabilities. We believe the open-source ecosystem deserves better tools, better auditing, and more support for the maintainers who keep it running. More findings will be published as patches ship and coordinated disclosure timelines are met.
If you are a maintainer and have been contacted by our team — thank you for your work. If you believe your package may be affected by a similar pattern, we’d love to help: securityresearch@codeant.ai
FAQs
What is this vulnerability?
What versions of yauzl are affected?
Who discovered this vulnerability?
How do I check if my application is vulnerable?
How do I fix it?
Is this as severe as CVE-2026-28292 (simple-git) or CVE-2026-29000 (pac4j)







