VYPR
Medium severityOSV Advisory· Published Oct 30, 2025· Updated Apr 15, 2026

CVE-2025-64118

CVE-2025-64118

Description

node-tar is a Tar for Node.js. In 7.5.1, using .t (aka .list) with { sync: true } to read tar entry contents returns uninitialized memory contents if tar file was changed on disk to a smaller size while being read. This vulnerability is fixed in 7.5.2.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
tarnpm
>= 7.5.1, < 7.5.27.5.2

Affected products

1

Patches

2
5e1a8e638600

Fix sync tar.list when file size reduces while reading

https://github.com/isaacs/node-tarisaacsOct 30, 2025via ghsa
2 files changed · +96 3
  • src/list.ts+3 2 modified
    @@ -64,13 +64,14 @@ const listFileSync = (opt: TarOptionsSyncFile) => {
         const readSize: number = opt.maxReadSize || 16 * 1024 * 1024
         if (stat.size < readSize) {
           const buf = Buffer.allocUnsafe(stat.size)
    -      fs.readSync(fd, buf, 0, stat.size, 0)
    -      p.end(buf)
    +      const read = fs.readSync(fd, buf, 0, stat.size, 0)
    +      p.end(read === buf.byteLength ? buf : buf.subarray(0, read))
         } else {
           let pos = 0
           const buf = Buffer.allocUnsafe(readSize)
           while (pos < stat.size) {
             const bytesRead = fs.readSync(fd, buf, 0, readSize, pos)
    +        if (bytesRead === 0) break
             pos += bytesRead
             p.write(buf.subarray(0, bytesRead))
           }
    
  • test/list.ts+93 1 modified
    @@ -1,4 +1,4 @@
    -import fs, { readFileSync } from 'fs'
    +import fs, { readFileSync, Stats } from 'fs'
     //@ts-ignore
     import mutateFS from 'mutate-fs'
     import { dirname, resolve } from 'path'
    @@ -7,6 +7,7 @@ import { fileURLToPath } from 'url'
     import { list } from '../dist/esm/list.js'
     import { Parser } from '../dist/esm/parse.js'
     import { ReadEntry } from '../dist/esm/read-entry.js'
    +import { makeTar } from './fixtures/make-tar.js'
     
     const __filename = fileURLToPath(import.meta.url)
     const __dirname = dirname(__filename)
    @@ -276,3 +277,94 @@ t.test('typechecks', t => {
       t.type(p, Parser)
       t.end()
     })
    +
    +// GHSA-29xp-372q-xqph
    +t.test('reduce file size while synchronously reading', async t => {
    +  const data = makeTar([
    +    {
    +      type: 'File',
    +      path: 'a',
    +      size: 1,
    +    },
    +    'a',
    +    {
    +      type: 'File',
    +      path: 'b',
    +      size: 1,
    +    },
    +    'b',
    +    '',
    +    '',
    +  ])
    +  const dataLen = data.byteLength
    +  const truncLen = 512 * 2
    +  const truncData = data.subarray(0, truncLen)
    +
    +  const setup = async (t: Test) => {
    +    const dir = t.testdir({ 'file.tar': data })
    +    const file = resolve(dir, 'file.tar')
    +    const { list } = await t.mockImport<
    +      typeof import('../src/list.js')
    +    >('../src/list.js', {
    +      'node:fs': t.createMock(fs, {
    +        fstatSync: (fd: number): Stats => {
    +          const st = fs.fstatSync(fd)
    +          // truncate the file before we have a chance to read
    +          fs.writeFileSync(file, truncData)
    +          return st
    +        },
    +      }),
    +    })
    +
    +    return { file, list }
    +  }
    +
    +  t.test(
    +    'gutcheck, reading normally reads the whole file',
    +    async t => {
    +      const dir = t.testdir({ 'file.tar': data })
    +      const file = resolve(dir, 'file.tar')
    +      const entries: string[] = []
    +      list({
    +        file,
    +        sync: true,
    +        maxReadSize: dataLen + 1,
    +        onReadEntry: e => entries.push(e.path),
    +      })
    +      t.strictSame(entries, ['a', 'b'])
    +
    +      entries.length = 0
    +      list({
    +        file,
    +        sync: true,
    +        maxReadSize: dataLen - 1,
    +        onReadEntry: e => entries.push(e.path),
    +      })
    +      t.strictSame(entries, ['a', 'b'])
    +    },
    +  )
    +
    +  t.test('read in one go', async t => {
    +    const { file, list } = await setup(t)
    +    const entries: string[] = []
    +    list({
    +      file,
    +      sync: true,
    +      maxReadSize: dataLen + 1,
    +      onReadEntry: e => entries.push(e.path),
    +    })
    +    t.strictSame(entries, ['a'])
    +  })
    +
    +  t.test('read in parts', async t => {
    +    const { file, list } = await setup(t)
    +    const entries: string[] = []
    +    list({
    +      file,
    +      sync: true,
    +      maxReadSize: dataLen / 4,
    +      onReadEntry: e => entries.push(e.path),
    +    })
    +    t.strictSame(entries, ['a'])
    +  })
    +})
    
5330eb04bc43

fix: consistent TOCTOU behavior in sync t.list

https://github.com/isaacs/node-tarfabasoadSep 22, 2025via ghsa
1 file changed · +7 5
  • src/list.ts+7 5 modified
    @@ -57,16 +57,18 @@ export const filesFilter = (opt: TarOptions, files: string[]) => {
     const listFileSync = (opt: TarOptionsSyncFile) => {
       const p = new Parser(opt)
       const file = opt.file
    -  let fd
    +  let fd: number | undefined
       try {
    -    const stat = fs.statSync(file)
    -    const readSize = opt.maxReadSize || 16 * 1024 * 1024
    +    fd = fs.openSync(file, 'r')
    +    const stat: fs.Stats = fs.fstatSync(fd)
    +    const readSize: number = opt.maxReadSize || 16 * 1024 * 1024
         if (stat.size < readSize) {
    -      p.end(fs.readFileSync(file))
    +      const buf = Buffer.allocUnsafe(stat.size)
    +      fs.readSync(fd, buf, 0, stat.size, 0)
    +      p.end(buf)
         } else {
           let pos = 0
           const buf = Buffer.allocUnsafe(readSize)
    -      fd = fs.openSync(file, 'r')
           while (pos < stat.size) {
             const bytesRead = fs.readSync(fd, buf, 0, readSize, pos)
             pos += bytesRead
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.