# adm-zip extraction preserves SUID/SGID bits from untrusted ZIPs -> local privilege escalation

adm-zip with keepOriginalPermission=true applies attacker-controlled zip mode bits including setuid, so a root-run extraction yields a root-owned SUID binary for local privilege escalation.

- Payout: Research
- Severity: high
- Program: adm-zip
- Found by: Ahmed-Elmahgob
- Disclosed: 2026-09-29
- CVE: CVE-2026-102282
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-j5f4-cc29-5x44
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-j5f4-cc29-5x44
- Tags: area:cloud domain:infra domain:oss impact:privesc kind:research platform:ghsa sev:high tech:nodejs technique:source-review vuln:misconfiguration vuln:privilege-escalation

**Target:** npm library adm-zip extractAllTo/extractEntryTo file extraction
**Root cause:** entryHeader.fileAttr masks external attributes with 0xfff (0o7777), preserving setuid/setgid/sticky bits, and utils.writeFileTo passes them unfiltered to fs.chmodSync when keepOriginalPermission is true.
**Steps:**
1. Craft zip with setuid mode: `zi.external_attr = 0o4755 << 16` on a ZipInfo entry containing a shell script.
2. Extract as root with flag: `new AdmZip('evil.zip').extractAllTo('/tmp/out', true, true)`.
3. Verify `fs.statSync('/tmp/out/pysuidbin').mode & 0o7777` equals `0o4755`; file is root-owned setuid.
4. Control: default extraction (keepOriginalPermission=false) yields mode 0666, no setuid.
**How found:** Code review of the fileAttr getter and writeFileTo path: noticed the 0xfff mask keeps special bits and that chmodSync receives the value unfiltered when the permission-preserving flag is set.
**Exploitation:** Attacker supplies crafted zip to an upload endpoint, fetched dependency archive, or build artifact; a root-running pipeline/CI/Docker step extracts it with keepOriginalPermission=true, producing a root-owned SUID binary that propagates via cp -a/rsync into runtime, where an unprivileged user executes it to gain root.
**Escalation:** Mode bits survive build-to-runtime propagation (cp -a/rsync), converting a file-write primitive into root code execution under build-as-root/run-as-user model.
**Insight:** When auditing archive extractors, check the mask applied to zip external_attr (>>16 & 0xfff vs 0o777) and whether chmod paths strip 0o7000; also check directory entries for setgid inheritance.

