# Arbitrary File Read/Write via Hardlink Target Escape Through Symlink Chain in node-tar Extraction

node-tar hardlink target resolved through a two-symlink chain escapes the extraction root, giving arbitrary file read/write as the extracting user.

- Payout: Research
- Severity: high
- Program: node-tar
- Found by: scumfrog
- Disclosed: 2026-02-18
- CVE: CVE-2026-26960
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-83g3-92jg-28cx
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-83g3-92jg-28cx
- Tags: area:oss domain:oss impact:data-leak impact:integrity kind:research platform:ghsa sev:high tech:nodejs technique:chained technique:source-review vuln:path-traversal

**Target:** npm tar library tar.extract() with default options
**Root cause:** Hardlink linkpath safety checks are string-based and never resolve on-disk symlinks; the target is resolved with path.resolve(cwd, entry.linkpath) and passed to fs.link, while parent-directory symlink checks apply only to the destination path, not the resolved target.
**Steps:**
1. Craft archive entries: symlink `a/b/c/up -> ../..`
2. Add symlink `a/b/escape -> c/up/../..`
3. Add hardlink `exfil -> a/b/escape/<target-relative-to-parent-of-extract>`
4. Extract with `tar.extract({ file, cwd })` defaults
5. Observe `same_inode=true`, `read_ok=true`, `write_ok=true` — exfil shares inode with external file
**How found:** Code review of unpack.js: noticed STRIPABSOLUTEPATH linkpath checks are string-based, hardlink target uses path.resolve + fs.link, and mkdir/symlink parent checks cover only the destination — hypothesized a symlink chain could redirect the resolved target outside root.
**Exploitation:** Attacker supplies a tar archive to any service extracting with default options; extraction creates `exfil` inside the root hardlinked to a file outside it, so the attacker reads or overwrites that file with the extracting process's privileges.
**Escalation:** Impact scales with deployment context: readable keys/configs/scripts or overwritable files reachable by the process user.
**Insight:** When auditing archive extractors, check whether link-target validation resolves symlinks on disk versus only normalizing strings; a symlink chain ending in `../..` can make a later hardlink's resolved target land outside the root even when the destination path passes checks.

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

**Symlink chain and hardlink escape archive entries**

```
1. `a/b/c/up -> ../..`
2. `a/b/escape -> c/up/../..`
3. `exfil` (hardlink) -> `a/b/escape/<target-relative-to-parent-of-extract>`
```

**Command running the hardlink PoC script**

```
TAR_MODULE="$(cd '../tar-audit-setuid - CVE/node_modules/tar' && pwd)" node hardlink.js
```

