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.
The bypass chain uses two symlinks plus one hardlink:
a/b/c/up -> ../..a/b/escape -> c/up/../..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.
STRIPABSOLUTEPATH logic 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:281Hardlink extraction resolves target as path.resolve(cwd, entry.linkpath) and then calls fs.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:703Parent 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:101As 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.
hardlink.js Environment used for validation:
v25.4.07.5.7tar.extract({ file, cwd }))Steps:
Prepare/locate a tar module. If require('tar') is not available locally, set TAR_MODULE to an absolute path to a tar package directory.
Run:
TAR_MODULE="$(cd '../tar-audit-setuid - CVE/node_modules/tar' && pwd)" node hardlink.js
same_inode=true
read_ok=true
write_ok=true
result=VULNERABLE
Interpretation:
same_inode=true: extracted exfil and external secret are the same file object.read_ok=true: reading exfil leaks external content.write_ok=true: writing exfil modifies external file.Vulnerability type:
Who is impacted:
tar defaults.Potential outcomes:
{
"cwe_ids": [
"CWE-22"
],
"nvd_published_at": "2026-02-20T02:16:53Z",
"github_reviewed_at": "2026-02-18T00:57:13Z",
"github_reviewed": true,
"severity": "HIGH"
}