Tar-pit of Doom: Escaping the Root in node-tar
Jan 16, 2026·6 min read
Executive Summary (TL;DR)
node-tar <= 7.5.2 failed to sanitize the targets of hardlinks and symlinks. If an archive contains a link pointing to an absolute path (e.g., `/etc/passwd`), node-tar would happily create it, ignoring the intended extraction directory. This leads to Arbitrary File Overwrite and potential RCE via config file manipulation.
A critical path traversal vulnerability in the ubiquitous node-tar library allows malicious archives to bypass extraction root restrictions. By manipulating hardlink and symlink targets with absolute paths, attackers can overwrite arbitrary system files or poison symbolic links, effectively turning a standard unzip operation into a weaponized file system assault.
The Hook: When 'Unzip' becomes 'Pwn'
We take extraction libraries for granted. You run npm install, you unzip a backup, you pull an artifact in your CI/CD pipeline. Under the hood, specifically in the Node.js ecosystem, node-tar is the workhorse doing the heavy lifting. It’s supposed to be a boring, reliable utility. It takes a stream of bytes and turns them into files on your disk.
However, the golden rule of archive extraction is containment. When I tell the library to extract evil.tar into ./output, I expect every single file to land inside ./output. If a file lands in /etc/, the library has failed its one job. This is the contract of the preservePaths: false setting (which is the default, secure mode).
CVE-2026-23745 is a breach of that contract. It turns out that while node-tar was very careful about where it placed files, it was completely negligent about what those files pointed to. It’s like a bouncer checking your ID at the door but ignoring the loaded bazooka slung over your shoulder.
The Flaw: Absolute Power Corrupts Absolute Paths
The vulnerability stems from a fundamental misunderstanding of how Node.js handles path resolution, mixed with a lapse in input validation coverage. The issue resides specifically in how Link (hardlink) and SymbolicLink entries are handled.
In Node.js, path.resolve(from, to) is the standard way to resolve paths. However, it has a quirk that trips up developers constantly: if the second argument is an absolute path, the first argument is ignored completely.
[!NOTE]
path.resolve('/safe/dir', '/etc/passwd')returns/etc/passwd, NOT/safe/dir/etc/passwd.
node-tar used this logic to determine where to create a hardlink. It took the current working directory (this.cwd) and tried to resolve the entry.linkpath (the target of the link) against it. Because the developer didn't check if entry.linkpath was absolute before passing it to resolve, an attacker could craft a TAR header saying: "I am a hardlink. Please link me to /root/.ssh/authorized_keys."
For symlinks, it was even lazier. The code simply passed the raw linkpath from the TAR header directly to fs.symlink. No questions asked. If the header said symlink -> /etc/shadow, node-tar obliged.
The Code: Anatomy of a Screw-Up
Let's look at the crime scene in src/unpack.ts. The validation routine [CHECKPATH] was guarding the front door (entry.path), but the back door (entry.linkpath) was left wide open.
The Vulnerable Logic (Conceptual):
// Hardlink handling
if (entry.type === 'Link') {
// THE BUG: If entry.linkpath is absolute, target becomes absolute
// ignoring this.cwd entirely.
const target = path.resolve(this.cwd, entry.linkpath);
fs.link(target, entry.absolute, cb);
}
// Symlink handling
if (entry.type === 'SymbolicLink') {
// THE BUG: entry.linkpath is passed raw to the filesystem
fs.symlink(entry.linkpath, entry.absolute, cb);
}The Fix (Commit 340eb28):
The patch introduces a unified sanitizer, [STRIPABSOLUTEPATH]. This method explicitly strips out root indicators (like leading slashes or drive letters) and strictly validates that the path doesn't try to traverse upwards using ...
Crucially, the patch applies this check to both properties:
// The Fix: Validate BOTH destination and link source
if (
!this[STRIPABSOLUTEPATH](entry, 'path') ||
!this[STRIPABSOLUTEPATH](entry, 'linkpath') // <--- The critical addition
) {
return false // Abort extraction if dirty
}This forces the linkpath to be relative to the extraction root, effectively jailing the operation back to the intended directory.
The Exploit: Smashing the Filesystem
To exploit this, we don't need buffer overflows or ROP chains. We just need to understand the TAR format. We can manually craft a header that lies about its link target.
Attack Scenario: The Config Overwrite
Imagine a CI/CD pipeline that extracts a user-provided tarball to lint the code. The runner creates a temporary directory, extracts the files, and then cleans up.
- Preparation: Attacker creates a malicious TAR.
- Entry 1: Type
Link(Hardlink). - Path:
temp_extraction/harmless.txt - LinkPath:
/home/runner/.bashrc(Targeting the runner's shell config)
- Entry 1: Type
- Execution: The pipeline runs
tar.x({ file: 'malicious.tar', cwd: './temp' }). - Trigger:
node-tarsees the hardlink request. It executeslink('/home/runner/.bashrc', './temp/harmless.txt').- Now,
harmless.txtand.bashrcare the same inode.
- Now,
- The Kill: If the pipeline (or the attacker via a second file entry) writes anything to
harmless.txt, it instantly overwrites.bashrc.
Here is the visual flow of the attack:
This allows an attacker to achieve persistence or RCE the next time a shell is spawned on that machine.
The Impact: Why You Should Panic (Slightly)
This isn't just about overwriting a text file. The implications depend heavily on who is extracting the archive and where.
- CI/CD Poisoning: As described above, overwriting
.bashrc,.ssh/authorized_keys, or/etc/hostson a build agent allows for lateral movement and supply chain injection. - Server-Side Extraction: If a web application accepts a TAR upload (e.g., "Upload your portfolio!") and extracts it to serve static files, an attacker can create a symlink to
/etc/passwdnamedportfolio/index.html. When the web server tries to serveindex.html, it reads the password file instead. - Dependency Confusion:
node-taris used bynpmitself (thoughnpmusually validates package contents strictly). However, custom tooling that wrapsnode-taris highly vulnerable.
The CVSS 4.0 score is 8.2 (High) because while it requires local interaction (uploading a file), the complexity is low and the impact on Confidentiality and Integrity is high.
The Fix: Stop the Bleeding
The remediation is straightforward, but urgency is required due to the ubiquity of the library.
Immediate Action:
Update node-tar to version 7.5.3 or higher immediately. Check your package-lock.json or yarn.lock because this library is likely deeply nested in your dependency tree.
npm install node-tar@latest
# Or if it is a sub-dependency
npm update node-tar --depth 99Defensive Coding:
If you are using node-tar programmatically, ensure you are NOT setting preservePaths: true unless you absolutely trust the source of the archive. That setting explicitly disables protections.
Also, consider validating the contents of archives before extraction using a stream parser to check for suspicious Link or SymbolicLink targets starting with / or containing ...
Official Patches
Fix Analysis (1)
Technical Appendix
CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:A/VC:H/VI:L/VA:N/SC:H/SI:L/SA:NAffected Systems
Affected Versions Detail
| Product | Affected Versions | Fixed Version |
|---|---|---|
node-tar isaacs | <= 7.5.2 | 7.5.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22 (Path Traversal) |
| CVSS 4.0 | 8.2 (High) |
| Attack Vector | Local (Archive Upload) |
| Affected Components | unpack.ts (Link/SymbolicLink handling) |
| Impact | Arbitrary File Overwrite / Symlink Poisoning |
| Exploit Status | Proof of Concept Available |
MITRE ATT&CK Mapping
The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
Known Exploits & Detection
Vulnerability Timeline
Subscribe to updates
Get the latest CVE analysis reports delivered to your inbox.