Arbitrary File Read/Write via Hardlink Target Escape Through Symlink Chain in node-tar Extraction
Published 18 Feb 2026 · Updated 10 Sept 2026
Affected package
- Affected
- <7.5.8
- Fixed in
- 7.5.8
npm install tar@7.5.8Details
Summary
tar.extract() in Node tar allows an attacker-controlled archive to create a hardlink inside the extraction directory that points to a file outside the extraction root, using default options.
This enables arbitrary file read and write as the extracting user (no root, no chmod, no preservePaths).
Severity is high because the primitive bypasses path protections and turns archive extraction into a direct filesystem access primitive.
Details
The bypass chain uses two symlinks plus one hardlink:
1. a/b/c/up -> ../..
2. a/b/escape -> c/up/../..
3. exfil (hardlink) -> a/b/escape/<target-relative-to-parent-of-extract>
Why this works:
- Linkpath checks are string-based and do not resolve symlinks on disk for hardlink target safety.
- See
STRIPABSOLUTEPATHlogic in: ../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/unpack.js:255../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/unpack.js:268../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/unpack.js:281
- Hardlink extraction resolves target as
path.resolve(cwd, entry.linkpath)and then callsfs.link(target, destination). ../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/unpack.js:566../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/unpack.js:567../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/unpack.js:703
- Parent directory safety checks (
mkdir+ symlink detection) are applied to the destination path of the extracted entry, not to the resolved hardlink target path. ../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/unpack.js:617../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/unpack.js:619../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/mkdir.js:27../tar-audit-setuid - CVE/node_modules/tar/dist/commonjs/mkdir.js:101
As a result, exfil is created inside extraction root but linked to an external file. The PoC confirms shared inode and successful read+write via exfil.
PoC
hardlink.js Environment used for validation:
- Node:
v25.4.0 - tar:
7.5.7 - OS: macOS Darwin 25.2.0
- Extract options: defaults (
tar.extract({ file, cwd }))
Steps:
1. Prepare/locate a tar module. If require('tar') is not available locally, set TAR_MODULE to an absolute path to a tar package directory.
2. Run:
TAR_MODULE="$(cd '../tar-audit-setuid - CVE/node_modules/tar' && pwd)" node hardlink.js
3. Expected vulnerable output (key lines):
same_inode=true read_ok=true write_ok=true result=VULNERABLE
Interpretation:
same_inode=true: extractedexfiland external secret are the same file object.read_ok=true: readingexfilleaks external content.write_ok=true: writingexfilmodifies external file.
Impact
Vulnerability type:
- Arbitrary file read/write via archive extraction path confusion and link resolution.
Who is impacted:
- Any application/service that extracts attacker-controlled tar archives with Node
tardefaults. - Impact scope is the privileges of the extracting process user.
Potential outcomes:
- Read sensitive files reachable by the process user.
- Overwrite writable files outside extraction root.
- Escalate impact depending on deployment context (keys, configs, scripts, app data).
Is GHSA-83g3-92jg-28cx in any of your client repos?
Checking one package by hand is fine. Checking it across forty client projects is not. NPMscan reads the lockfiles in every GitHub repo you pick, finds each project with an affected tar, and gives you the command that fixes it.
References
- Linkgithub.com/isaacs/node-tar/security/advisories/GHSA-83g3-92jg-28cx
- Advisorynvd.nist.gov/vuln/detail/CVE-2026-26960
- Linkgithub.com/isaacs/node-tar/commit/2cb1120bcefe28d7ecc719b41441ade59c52e384
- Linkgithub.com/isaacs/node-tar/commit/d18e4e1f846f4ddddc153b0f536a19c050e7499f
- Packagegithub.com/isaacs/node-tar
Advisory data from OSV.dev (opens OSV.dev in a new tab), refreshed daily.