{"id":15291,"library":"yauzl","title":"yauzl - Node.js Zip File Reader","description":"yauzl (yet another unzip library) is a Node.js package designed for reading and extracting `.zip` archives. It strictly adheres to the ZIP specification, differentiating itself by reading the central directory for file metadata rather than scanning for local file headers, which are prone to being out of sync with the central directory. The library emphasizes non-blocking, asynchronous APIs and efficient memory usage, particularly through its `lazyEntries` option, which prevents buffering entire files or all entries into RAM simultaneously. Version 3.3.0 is the current stable release, with the project demonstrating a healthy and positive release cadence, with updates typically occurring every few months. Key differentiators include robust error handling, built-in validation to guard against unsafe file names and potential zip bomb attacks, and support for non-conformant zip files created by certain Microsoft tools. The API is callback-based, making it suitable for event-driven Node.js applications.","status":"active","version":"3.3.0","language":"javascript","source_language":"en","source_url":"https://github.com/thejoshwolfe/yauzl","tags":["javascript","unzip","zip","stream","archive","file"],"install":[{"cmd":"npm install yauzl","lang":"bash","label":"npm"},{"cmd":"yarn add yauzl","lang":"bash","label":"yarn"},{"cmd":"pnpm add yauzl","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Utility for slicing file descriptors, bundled and used internally for file system operations.","package":"fd-slicer","optional":false}],"imports":[{"note":"While primarily a CommonJS module, Node.js allows importing it as a default export in ESM environments. For older Node.js versions or strict CJS, use require().","wrong":"const yauzl = require('yauzl'); // CommonJS in ESM context without adapter","symbol":"yauzl","correct":"import yauzl from 'yauzl';"},{"note":"The primary `open` function is a method on the `yauzl` default export.","wrong":"import { open } from 'yauzl'; // Not a named export for the main function.","symbol":"open","correct":"import yauzl from 'yauzl'; yauzl.open(...);"},{"note":"The `ZipFile` class, if needed directly for advanced usage, is available as a property of the main `yauzl` module object. It's usually instantiated internally by `yauzl.open`.","wrong":"import { ZipFile } from 'yauzl'; // Not a named export","symbol":"ZipFile","correct":"import yauzl from 'yauzl'; // Access ZipFile class via yauzl.ZipFile"}],"quickstart":{"code":"import * as fs from 'fs';\nimport * as path from 'path';\nimport yauzl from 'yauzl';\n\nconst zipFilePath = 'path/to/your/archive.zip';\nconst extractDir = 'path/to/extract/to';\n\nfs.mkdirSync(extractDir, { recursive: true });\n\nyauzl.open(zipFilePath, { lazyEntries: true, autoClose: true }, (err, zipfile) => {\n  if (err) throw err;\n\n  zipfile.on('entry', (entry) => {\n    const entryPath = path.join(extractDir, entry.fileName);\n    if (//$/.test(entry.fileName)) {\n      // Directory file names end with '/'\n      fs.mkdirSync(entryPath, { recursive: true });\n      zipfile.readEntry();\n    } else {\n      // File entry\n      zipfile.openReadStream(entry, (err, readStream) => {\n        if (err) throw err;\n        readStream.on('end', () => {\n          zipfile.readEntry();\n        });\n        // Ensure parent directory exists for the file\n        fs.mkdirSync(path.dirname(entryPath), { recursive: true });\n        readStream.pipe(fs.createWriteStream(entryPath));\n      });\n    }\n  });\n\n  zipfile.on('end', () => {\n    console.log('Zip extraction complete.');\n  });\n\n  // Start reading entries\n  zipfile.readEntry();\n});","lang":"javascript","description":"Demonstrates how to open a zip file, process entries one by one using `lazyEntries`, handle both files and directories, and stream content to disk."},"warnings":[{"fix":"Ensure your Node.js environment is version 12 or newer. If implementing a custom `RandomAccessReader`, rename the `destroy` method to `_destroy` and update its signature to `_destroy(err, callback)`.","message":"Version 3.0.0 introduced breaking changes, including dropping support for Node.js versions older than 12. Additionally, implementations of `RandomAccessReader` (for custom back-ends) must now implement a `_destroy` method instead of `destroy` to align with Node.js stream standards.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Upgrade `yauzl` to version 3.3.0 or higher immediately. This fix addresses the vulnerability and prevents application crashes from malformed zip files.","message":"CVE-2026-31988: A denial of service vulnerability exists in `yauzl` version 3.2.0 due to an off-by-one error in a timestamp parser. Processing a specially crafted zip file could crash the Node.js process.","severity":"breaking","affected_versions":"3.2.0"},{"fix":"Always set `lazyEntries: true` in the `options` object when calling `yauzl.open()`, and manually call `zipfile.readEntry()` after processing each entry to control memory usage.","message":"The `lazyEntries` option defaults to `false`. While this allows piping file data from all entries in parallel, it can lead to excessive memory consumption for zip files containing many entries. For better memory control, especially with large archives, `lazyEntries: true` is highly recommended.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Keep `validateEntrySizes` set to `true` (the default). If you must disable it, implement custom heuristics for size validation and error handling to mitigate risks from malicious or malformed zip files.","message":"The `validateEntrySizes` option defaults to `true` and ensures an entry's reported uncompressed size matches its actual size, which helps defend against zip bomb attacks. Disabling this option (setting it to `false`) removes this crucial validation, potentially exposing the application to exploits or unexpected behavior from malformed archives.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Consider the origin of your zip files. If interoperability with Microsoft-created zip files is necessary, leave `strictFileNames: false`. If strict adherence to the ZIP spec regarding filenames is critical, set `strictFileNames: true` and handle potential errors for invalid filenames.","message":"The `strictFileNames` option defaults to `false`. This default behavior replaces backslashes (`\\`) in `entry.fileName` with forward slashes (`/`), allowing `yauzl` to read non-conformant zip files created by some Microsoft tools. If `strictFileNames` is set to `true`, entries with backslashes will result in an error when `decodeStrings` is also `true`.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Unless you have a specific need to handle raw filename buffers (e.g., custom encoding), keep `decodeStrings: true` for proper string decoding and automatic filename validation.","message":"The `decodeStrings` option defaults to `true`, causing `yauzl` to decode filenames and comments using CP437 or UTF-8. If set to `false`, `entry.fileName`, `entry.fileComment`, and `zipfile.comment` will be `Buffer` objects instead of strings, and automatic filename validation (via `validateFileName()`) will be bypassed.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"Set `lazyEntries: true` when opening the zip file and manually call `zipfile.readEntry()` after each entry's data stream has finished processing.","cause":"`lazyEntries` option was `false`, leading to all entries being buffered or processed too quickly for large zip files or those with many small entries.","error":"JavaScript heap out of memory"},{"fix":"Verify that the input file is indeed a valid and uncorrupted `.zip` archive. Check file integrity or source.","cause":"The input file is not a valid ZIP archive, or it's severely corrupted, preventing `yauzl` from locating the central directory.","error":"Error: Invalid or unsupported zip file. (End of Central Directory Record not found)"},{"fix":"Inspect `entry.fileName`. If the name is genuinely unsafe, reject the entry. If backslashes are the issue and expected from non-conformant zips, ensure `strictFileNames: false` (the default) and `decodeStrings: true`.","cause":"`yauzl`'s `validateFileName()` detected characters or patterns (like absolute paths, `..` segments, or backslashes with `strictFileNames: true`) that are considered unsafe for extraction.","error":"Error: Entry filename contains unsafe characters"},{"fix":"This indicates a corruption within the zip file's contents for a specific entry. The zip file itself might be damaged. There is no code fix for a corrupted source file; you may need to acquire an uncorrupted archive.","cause":"The zlib decompression stream encountered corrupted or invalid compressed data for a file entry.","error":"Error: Z_DATA_ERROR: incorrect header check"},{"fix":"Handle the error gracefully. This is a security feature. The zip file might be intentionally malicious or simply corrupted. Ensure `yauzl` is updated to the latest stable version to benefit from all fixes and validations.","cause":"`validateEntrySizes` was `true` (default) and the actual uncompressed size of an entry did not match the size reported in the zip file's metadata, potentially indicating a zip bomb or corrupted data.","error":"RangeError: Zip entry size mismatch"}],"ecosystem":"npm"}