All vulnerabilities
GHSA-p634-w6r4-rjp2CVE-2026-114104

adm-zip: Duplicate ZIP entry names: getEntry() and extractAllTo() resolve to different content

adm-zipnpmLibraries & packages
CVSS
5.9Medium
ExploitationNo known exploitationNot in CISA KEV, which does not prove it is unexploitedCISA KEV
Exploit odds (EPSS)No scoreNo FIRST EPSS score in this snapshot yet
Fixed in0.6.1Fixed versionGitHub
Published29 Sep 2026Updated 21 Oct 2026GitHub

What fixes it

  • 0.6.1adm-zip, npmGitHubnpm install adm-zip@0.6.1

A fixed version on one release line is not the upgrade target for every line. Check your exact version and any vendor backports.

Description

Summary

A ZIP file can contain two entries with the identical name. adm-zip keeps both in its internal entry list, but its name-lookup table only retains the last one written. getEntry(name) and extractAllTo() walk these two different internal structures, so they can each resolve a duplicate name to a *different* entry. An application that validates a named entry's contents via getEntry() before trusting an archive, then extracts the whole archive, can end up approving one file's content while a different file's bytes are what actually land on disk under that name.

Details

  • zipFile.js:58-83 retains both entries in entryList but overwrites entryTable[name] with only the last one written.
  • adm-zip.js:83-95,658-663 uses entryTable for getEntry() lookups โ€” returns the *last* duplicate.
  • adm-zip.js:769-914 iterates entryList for extraction โ€” writes the *first* duplicate (sync, default overwrite policy).

PoC

const AdmZip = require('adm-zip');
const z = new AdmZip({ noSort: true });
z.addFile('a.txt', Buffer.from('FIRST'));
z.addFile('b.txt', Buffer.from('SECOND'));
const raw = Buffer.from(z.toBuffer());
// rename the a.txt entry to b.txt directly in the raw bytes
for (let at = raw.indexOf('a.txt'); at >= 0; at = raw.indexOf('a.txt', at + 5)) {
  raw.write('b.txt', at);
}
const parsed = new AdmZip(raw, { noSort: true });
const validated = parsed.getEntry('b.txt').getData().toString();
parsed.extractAllTo(outDir, false);
// validated === "SECOND", but the file written to disk === "FIRST"

Reproduced on the pinned commit (2b4d84087d45344643e0183756e19191d52815cc)

Impact

An application that checks a named entry's content before trusting an untrusted ZIP, then extracts it, can be made to approve different bytes than what actually gets written to disk โ€” the classic check/use split that this kind of validate-then-extract pattern relies on.

Text from GitHub Advisory Database

Affected versions 2

  • adm-zip, npm<= 0.6.0GitHub
  • adm-zip, npmfrom first release, fixed in 0.6.1OSV

References 4