# 5 RCEs in npm for $15,000

Multiple path-handling flaws in node-tar and npm's arborist let malicious tarballs write arbitrary files outside the extraction directory during npm install, even with --ignore-scripts.

- Payout: $15,000
- Severity: high
- Program: -
- Credited: Robert Chen, Philip
- Disclosed: 2021-09-20
- CVE: CVE-2021-32804, CVE-2021-32803, CVE-2021-37701, CVE-2021-37712, CVE-2021-37713, CVE-2021-39134
- Write-up quality: 9/10
- Original: https://robertchen.cc/blog/2021/09/20/npm-rce
- Library page: https://bugbountylibrary.com/r/blog%3Arobertchen-cc-blog-2021-09-20-npm-rce
- Tags: domain:oss impact:integrity impact:rce kind:bounty platform:blog sev:high tech:nodejs technique:parser-differential technique:source-review technique:unicode-normalization vuln:file-upload vuln:path-traversal

**Target:** npm CLI package tarball extraction (node-tar, @npmcli/arborist)
**Root cause:** Absolute-path stripping used a naive substring on path.win32.parse root, and the directory cache could desynchronize from the filesystem via symlink deletion, backslash/forward-slash mismatch, or NFD unicode normalization, skipping symlink checks.
**Steps:**
1. CVE-2021-32804: craft tar entry path `///tmp/pwned`; path.win32.parse root is `/`, substr leaves `//tmp/pwned`, which fs resolves to `/tmp/pwned`
2. CVE-2021-32803: use `C:../a` style path; stripAbsolutePath leaves it non-absolute but path.resolve treats `C:` as drive-relative, escaping one directory up
3. CVE-2021-32803 escalation: symlink package AAAA to target dir, extract `C:../AAAA/overwrite` (racey)
4. CVE-2021-37701: tar with MKDIR `x`, then SYMLINK `x -> /tmp` (deletes dir without purging dirCache), then FILE `x/pwned`
5. CVE-2021-37712: on Windows create dir `.../test-unpack/x` (cache stores forward slash) then remove via `...\test-unpack\x` so prune check misses; on Unix use symlink named `a\x`
6. CVE-2021-37713: on macOS create folder `\u00e9`, symlink `\u0065\u0301` (NFD-normalized to same file, deletes folder without cache purge), then write `\u00e9/pwned`
7. Publish malicious tarball via PUT to registry.npmjs.org; victim `npm install` extracts and writes arbitrary file
**How found:** Started from GitHub npm CLI bounty scope item 'RCE breaking out of --ignore-scripts'; audited pacote, arborist, tar; noticed naive substr on path.win32.parse root looked suspicious, confirmed with node CLI that `//tmp/pwned` resolves absolute; then reasoned about dirCache as security-critical and hunted filesystem/cache inconsistencies (deletion, slash normalization, NFD).
**Exploitation:** Attacker publishes a package whose tarball contains crafted entry paths/symlinks; on victim npm install (extraction runs even with --ignore-scripts) node-tar writes attacker content to arbitrary filesystem paths, enabling overwrite of files like shell rc or executables for RCE.
**Escalation:** Chained relative-path overwrite with symlinked packages and race conditions to reach RCE; dirCache desync bypasses symlink checks to write anywhere.
**Insight:** When a security check strips a prefix via substring, test parser-differential inputs like `///x` and drive-relative `C:../x` against path.resolve; and treat any performance cache that gates security checks as a desync target via deletion, separator normalization, or unicode NFD.
