{"id":"GHSA-c6fg-446q-cg94","title":"adm-zip: getDataAsync() bypasses the maxOutputLength size guard enforced by the synchronous getData() path","summary":"adm-zip: getDataAsync() bypasses the maxOutputLength size guard enforced by the synchronous getData() path","severity":"medium","cvss":5.3,"cwe":["CWE-400","CWE-770"],"vendor":"adm-zip","product":"adm-zip","ecosystem":"npm","affected":["adm-zip <= 0.6.0"],"patched":["adm-zip 0.6.1"],"published":"2026-09-29","updated":"2026-09-29","sourceUpdated":"2026-09-29T23:10:35Z","source":"GHSA","sourceUrl":"https://github.com/advisories/GHSA-c6fg-446q-cg94","references":[{"url":"https://github.com/cthackers/adm-zip/security/advisories/GHSA-c6fg-446q-cg94"},{"url":"https://github.com/cthackers/adm-zip/commit/491600683dacb6cb9fe0718a0eeb9cb5eb49afa6"},{"url":"https://github.com/cthackers/adm-zip/releases/tag/v0.6.1"},{"url":"https://github.com/advisories/GHSA-c6fg-446q-cg94"}],"tags":["ghsa","npm"],"ingestedAt":"2026-09-29T23:52:50.542Z","slug":"GHSA-c6fg-446q-cg94","body":"## Overview\n\n### Summary\nadm-zip enforces a `maxOutputLength` guard against decompression bombs on its synchronous `getData()` path, but the equivalent asynchronous `getDataAsync()` path does not enforce it — it accumulates and returns the entire decompressed output regardless of the entry's declared size. An application that checks an entry's declared size before deciding to process it, then reads the entry via `getDataAsync()` (a completely ordinary, often-recommended choice for I/O in Node.js), gets none of the protection it believes it has.\n\n\n### Details\n\n- `methods/inflater.js:3-10` passes `{maxOutputLength: expectedLength}` to `inflateRawSync`, which Node enforces.\n- `methods/inflater.js:12-31` passes the same option to `createInflateRaw` but never enforces it on the streaming path — it just accumulates every chunk and allocates a final Buffer of whatever size resulted.\n\n\n### PoC\n\n```js\nconst AdmZip = require('adm-zip');\nconst zip = new AdmZip();\nzip.addFile('p', Buffer.alloc(64 * 1024 * 1024, 0x41)); // 64 MiB\nconst raw = Buffer.from(zip.toBuffer());\n// patch the local + central declared uncompressed size to 1 byte\nraw.writeUInt32LE(1, localHeaderSizeOffset);\nraw.writeUInt32LE(1, centralHeaderSizeOffset);\nconst entry = new AdmZip(raw).getEntry('p');\n\nentry.getData();\n// throws: ERR_BUFFER_TOO_LARGE: Cannot create a Buffer larger than 1 bytes\n\nentry.getDataAsync((data, error) => { ... });\n// returns the full 67,108,864-byte buffer, error is undefined\n```\n\n### Impact\nAn application that validates a declared size before reading an entry, then uses the async API, gets no protection against a high-ratio DEFLATE payload. Repeated or larger requests could contribute to memory exhaustion.\n\n## Affected packages\n\n- `adm-zip <= 0.6.0`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `adm-zip 0.6.1`","depth":"sunlit","depthScore":29,"depthScoreParts":{"impact":29.2,"likelihood":0,"exploitation":0,"ransomware":0},"changes":[]}