GHSA-p634-w6r4-rjp2

Suggest an improvement
Source
https://github.com/advisories/GHSA-p634-w6r4-rjp2
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-p634-w6r4-rjp2/GHSA-p634-w6r4-rjp2.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-p634-w6r4-rjp2
Published
2026-09-29T23:11:01Z
Modified
2026-09-29T23:15:08Z
Severity
  • 5.9 (Medium) CVSS_V3 - CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N CVSS Calculator
Summary
adm-zip: Duplicate ZIP entry names: getEntry() and extractAllTo() resolve to different content
Details

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.

Database specific
{
    "cwe_ids":  [
        "CWE-436",
        "CWE-696"
    ],
    "github_reviewed":  true,
    "github_reviewed_at":  "2026-09-29T23:11:01Z",
    "nvd_published_at":  null,
    "severity":  "MODERATE"
}
References

Affected packages

npm / adm-zip

Package

Affected ranges

Type
SEMVER
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
0.6.1

Database specific

last_known_affected_version_range
"<= 0.6.0"
source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-p634-w6r4-rjp2/GHSA-p634-w6r4-rjp2.json"