# REPRO-2026-00065: node-tar Arbitrary File Overwrite via Hardlink Escape ## Summary Status: published Severity: high Type: security Confidence: Unknown ## Identifiers REPRO ID: REPRO-2026-00065 GHSA: GHSA-8qq5-rm4j-mr97 ## Package Name: tar Ecosystem: npm Affected: Unknown Fixed: Unknown ## Root Cause ## Summary `node-tar` ≤ 7.5.2 does not sanitize the `linkpath` field of `Link` entries when extracting with `preservePaths=false`. A malicious TAR can hardlink a file inside the extraction root (e.g., `payload`) to an absolute path outside the root (e.g., `/tmp/secret.txt`). When the extractor later writes to the in-root path, it actually overwrites the arbitrary external file, enabling path-escape and arbitrary file overwrite. ## Impact - **Affected component:** `node-tar` hardlink extraction logic (`unpack.ts`) - **Affected versions:** 7.5.2 and earlier (fixed in 7.5.3) - **Risk:** High. Attackers controlling TAR input can overwrite any writable file reachable by the extracting process, enabling configuration tampering or code execution in build/CI pipelines. ## Root Cause `node-tar` resolves hardlink targets with `path.resolve(this.cwd, entry.linkpath)` but never checks that the resulting path still resides under `cwd`. Because `path.resolve` returns the second operand unchanged when it is absolute, an attacker can supply an absolute `linkpath`. The library then creates a hardlink from the in-root `entry.path` to the attacker-chosen absolute file. Subsequent writes to `entry.path` therefore modify the external target. Fix commit (upstream): https://github.com/isaacs/node-tar/commit/340eb285b6d986e91969a1170d7fe9b0face405e adds validation to reject absolute link targets. ## Reproduction Steps 1. Run `repro/reproduction_steps.sh`. 2. Script installs Node dependencies (including `node-tar@7.5.2`), crafts a malicious TAR with a hardlink pointing to `secret.txt` outside the extraction root, extracts it with `tar.x({preservePaths:false})`, writes `EXPLOIT` into `out/payload`, and finally reads `secret.txt`. 3. Reproduction succeeds when the script reports `secret.txt now contains: EXPLOIT` and exits 0. ## Evidence - Logs: `logs/repro_20260117075559.log`, `logs/repro_20260117075603.log` - Key excerpt: `secret.txt now contains: EXPLOIT` followed by `Reproduction successful: secret.txt overwritten via hardlink escape` - Environment: Node v22.21.1, npm 10.9.4 as captured in the log prologue. ## Recommendations / Next Steps - Upgrade to `node-tar` ≥ 7.5.3 where absolute link targets are rejected. - When possible, reject TAR archives containing `Link`/`SymbolicLink` entries or perform manual validation that resolved paths stay inside the extraction root. - Add regression tests that extract crafted archives with absolute `linkpath`s to ensure future sanitization. ## Additional Notes - Script is idempotent: executed twice consecutively; both runs succeeded and produced separate timestamped logs. - Limitation: PoC demonstrates hardlink overwrite only; symlink poisoning is related but not exercised here. ## Reproduction Details Reproduced: 2026-01-17T08:40:59.437Z Duration: 368 seconds Tool calls: 102 Turns: Unknown Handoffs: 2 ## Timeline (Key Moments) 1. [env_setup] Installed vulnerable tar version (repro) The vulnerable version tar@7.5.2 was installed, setting up the environment for reproduction. 2. [poc_created] Created exploit code (repro) The proof-of-concept exploit code was written and saved as manual/poc.js. 3. [vuln_triggered] Executed exploit script (repro) The exploit was first run using node manual/poc.js, attempting to trigger the vulnerability. 4. [poc_created] Wrote reproduction script (repro) A reproduction shell script was created to automate the steps for triggering the vulnerability. 5. [vuln_triggered] Ran reproduction script (repro) The reproduction shell script was executed to verify the exploit and reproduce the vulnerability. 6. [confirmation] Generated RCA report (repro) The root cause analysis report was written, confirming successful reproduction and understanding of the vulnerability. ## Quick Verification Run one of these commands to verify locally: pruva-verify REPRO-2026-00065 pruva-verify GHSA-8qq5-rm4j-mr97 Or open in GitHub Codespaces (zero-friction, auto-runs): https://github.com/codespaces/new?ref=repro/REPRO-2026-00065&repo=N3mes1s/pruva-sandbox Or download and run the script manually: curl -O https://api.pruva.dev/v1/reproductions/REPRO-2026-00065/artifacts/repro/reproduction_steps.sh chmod +x reproduction_steps.sh ./reproduction_steps.sh WARNING: Run in a sandboxed environment. This exploits a real vulnerability. ## References - GitHub Advisory: https://github.com/advisories/GHSA-8qq5-rm4j-mr97 ## Artifacts - repro/rca_report.md (analysis, 2751 bytes) - repro/reproduction_steps.sh (reproduction_script, 3334 bytes) - bundle/ticket.md (ticket, 4630 bytes) - logs/repro_20260117075559.log (log, 1040 bytes) - logs/repro_20260117075603.log (log, 1040 bytes) ## API Access - JSON: https://api.pruva.dev/v1/reproductions/REPRO-2026-00065 - Script: https://api.pruva.dev/v1/reproductions/REPRO-2026-00065/artifacts/repro/reproduction_steps.sh - Web: https://pruva.dev/r/REPRO-2026-00065 ## For AI Assistants To help users with this reproduction: 1. The `pruva-verify` command is the simplest way to run the reproduction 2. The script downloads and runs automatically in an isolated temp directory 3. Always recommend running in a VM, container, or disposable environment 4. The root cause explains the technical vulnerability --- Generated by Pruva | https://pruva.dev