TL;DR
CodeAnt AI Security Research discovered a Denial of Service (DoS) vulnerability in yauzl 3.2.0, the most widely used Node.js ZIP parsing library. A specially crafted ZIP file with malformed Central Directory entries triggers an unhandled exception that crashes the Node.js process entirely. Any application that processes user-supplied ZIP files using yauzl — including VS Code extension hosts, Electron apps, CI/CD pipelines, and file upload services — is potentially vulnerable to remote process termination.
| Property | Detail |
|---|---|
| Vulnerability Type | Denial of Service (DoS) via Unhandled Exception |
| Affected Package | yauzl |
| Affected Version | 3.2.0 (latest) |
| Severity | High |
| Attack Vector | Maliciously crafted ZIP file |
| Researcher | CodeAnt AI Security Research |
| Fix Available | No patch at time of publication |
What Is yauzl and Why Does It Matter?
If you have ever unzipped a file inside a Node.js application, there is a reasonable chance yauzl — short for "yet another unzip library" — did the heavy lifting. It is the de facto standard for ZIP file parsing in the Node.js ecosystem, depended upon by ~1,345 npm packages.
The library powers infrastructure you interact with every day:
-
VS Code — extensions are packaged as
.vsixfiles, which are ZIP archives. The extension host relies on yauzl to unpack and validate them. - Electron applications — many Electron-based apps ship update payloads or resource bundles as ZIP archives and use yauzl to extract them at runtime.
- CI/CD pipelines — build systems, artifact stores, and deployment tools routinely unpack ZIP archives as part of automated workflows.
- File upload services — SaaS platforms that accept ZIP uploads lean on yauzl for extraction.
- Developer tooling — bundlers, scaffolding tools, and package managers use yauzl as a core dependency.
The library ships with several safety-oriented features:
-
validateEntrySizes— guards against ZIP bomb decompression attacks. -
validateFileName— prevents path traversal exploits like../../etc/passwd. - Central Directory parsing — uses the ZIP spec's authoritative file index rather than local file headers.
Design principle #4 in the yauzl README explicitly states a commitment to Robustness — the idea that malformed ZIP files should never crash the host application. As we demonstrate below, that guarantee does not hold in version 3.2.0.
The Vulnerability
How yauzl Parses ZIP Files
ZIP files have a two-part structure. Each file entry has a Local File Header near the compressed data, but the authoritative index lives in the Central Directory at the end of the archive. yauzl reads the Central Directory first to enumerate entries.
const yauzl = require('yauzl');
yauzl.open('archive.zip', { lazyEntries: true }, (err, zipfile) => {
if (err) throw err;
zipfile.readEntry();
zipfile.on('entry', (entry) => {
zipfile.openReadStream(entry, (err, readStream) => {
if (err) throw err;
readStream.pipe(someWritableDestination);
readStream.on('end', () => zipfile.readEntry());
});
});
zipfile.on('end', () => console.log('Done'));
});
This is almost exactly the pattern shown in the official README — and the pattern most real-world consumers follow.
The Crash
A specially crafted ZIP file can embed a Central Directory entry where a critical numeric field contains an unexpected value that yauzl's parser does not defensively validate before using it in a downstream operation. When yauzl processes this entry, it passes the malformed value into a code path that does not guard against the anomaly, resulting in an unhandled exception thrown synchronously inside an asynchronous callback chain.
Because the exception is thrown outside a try/catch boundary and is not forwarded to the library's own error callback, the Node.js process receives an uncaught exception. Unless the host application has registered a global process.on('uncaughtException', ...) handler — which most production applications deliberately avoid — the process terminates immediately.
/path/to/node_modules/yauzl/index.js:NNN
throw new Error("...");
^
Error: [internal yauzl error triggered by malformed field]
at ...
Node.js process exited with code 1
The exit is abrupt and immediate. No graceful shutdown, no error forwarded to the application, no opportunity to log, alert, or recover.
Why the Existing Safeguards Do Not Help
-
validateEntrySizesprotects against decompression bombs — it checks during stream reading, not during Central Directory parsing, so it is never reached. -
validateFileNamechecks for path traversal patterns in the file name field. The malformed field triggering this vulnerability is a different field entirely. -
strictFileNamessanitizes file name characters. Unrelated to the affected field.
The vulnerability lives in parsing logic that runs before any of these guards are evaluated.
Impact Analysis
Who Is Affected
Any Node.js process that:
- Accepts ZIP files from untrusted or semi-trusted sources, and
- Opens them with
yauzl.open()oryauzl.fromBuffer(), and - Calls
readEntry()to enumerate the archive contents
...is vulnerable to process termination via a single crafted upload.
| Attack Scenario | Exploitable? | Notes |
|---|---|---|
| File upload endpoint (HTTP) | Yes | Single request terminates server process |
| CI/CD artifact ingestion | Yes | Poisoned build artifact crashes runner |
| VS Code extension installation | Yes | Crafted .vsix crashes extension host |
| Electron app auto-update | Yes | Malicious update payload crashes app |
| Email attachment processing | Yes | Triggered on message receipt |
| Offline ZIP processing | No | Attacker cannot supply the file |
CVSS Snapshot
| Metric | Value |
|---|---|
| Attack Vector | Network |
| Attack Complexity | Low |
| Privileges Required | None |
| User Interaction | None (server-side) / Required (client-side) |
| Availability Impact | High |
| Confidentiality Impact | None |
| Integrity Impact | None |
| Estimated CVSS Score | 7.5 (High) |
Remediation and Workarounds
Until an official patch is released:
1. Isolate ZIP Processing in a Child Process
const { fork } = require('child_process');
function safeExtract(zipPath, callback) {
const worker = fork('./zip-worker.js', [zipPath]);
worker.on('message', (msg) => callback(null, msg));
worker.on('error', (err) => callback(err));
worker.on('exit', (code) => {
if (code !== 0) {
callback(new Error(`ZIP worker exited with code ${code}`));
}
});
}
By processing ZIP files in a forked child process, a crash terminates only the worker — not your main server.
2. Validate ZIP Files Before Processing
const ZIP_MAGIC = Buffer.from([0x50, 0x4b, 0x03, 0x04]);
function looksLikeZip(buffer) {
return buffer.slice(0, 4).equals(ZIP_MAGIC);
}
3. Ensure Process Supervision
Ensure your Node.js processes are managed by a process supervisor (PM2, systemd, Kubernetes) with automatic restart policies.
4. Consider Alternative Libraries
-
unzipper— actively maintained, streams-based -
jszip— pure JavaScript, in-memory -
adm-zip— synchronous API, different trade-offs
Key Takeaways
- "Robustness" guarantees require adversarial testing. Security properties need to be tested with fuzzers, not just stated in documentation.
- Unhandled exceptions in async callbacks are process-killers. Libraries processing untrusted data must wrap every parsing operation defensively.
- Process isolation is a practical defense. Handle untrusted file formats in a child process to contain the blast radius.
-
Audit your dependency tree. Run
npm ls yauzlto understand your exposure. - ZIP is not a simple format. Treat ZIP ingestion with the same scrutiny you apply to SQL queries or HTML rendering.
Disclosure Timeline
| Date | Event |
|---|---|
| 2026-02-XX | Vulnerability discovered by CodeAnt AI Security Research |
| 2026-02-XX | Initial disclosure sent to yauzl maintainer |
| 2026-03-12 | Public disclosure |
| TBD | Patch released |
About CodeAnt AI
CodeAnt AI builds AI-powered code quality and security tools that help engineering teams ship safer software faster. Our security research team investigates vulnerabilities in widely used open-source libraries to help the broader developer community stay informed and protected.
- Product: codeant.ai
- Security Research: codeant.ai/security-research
Responsible disclosure is a core value at CodeAnt AI. We follow coordinated disclosure practices and work with maintainers to provide reasonable remediation timelines before public disclosure.
Top comments (0)