CVE-2024-28863 (JavaScript, published 2024-03-21T23:15Z)
Description: value: node-tar is a Tar for Node.js. node-tar prior to version 6.2.1 has no limit on the number of sub-folders created in the folder creation process. An attacker who generates a large number of sub-folders can consume memory on the system running node-tar and even crash the Node.js client within few seconds of running it using a path with too many sub-folders inside. Version 6.2.1 fixes this issue by preventing extraction in excessively deep sub-folders.
Severity: nan (CVSS v3 base score: )
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/isaacs/node-tar
Files changed:
README.md
lib/unpack.js
test/parse.js
test/unpack.js
Commit message: prevent extraction in excessively deep subfolders

This sets the limit at 1024 subfolders nesting by default, but that can
be dropped down, or set to Infinity to remove the limitation.


Vulnerable code:
      const parts = normPath(entry.path).split('/')
      entry.path = parts.slice(this.strip).join('/')

      const p = normPath(entry.path)
      const parts = p.split('/')
    t.same(warnings, ['zlib: incorrect data check'])

Fixed code:
  - an entry is trying to extract into an excessively deep
    location (by default, limited to 1024 subfolders),
- `maxDepth` The maximum depth of subfolders to extract into. This
  defaults to 1024. Anything deeper than the limit will raise a
  warning and skip the entry. Set to `Infinity` to remove the
  limitation.
- `maxDepth` The maximum depth of subfolders to extract into. This
  defaults to 1024. Anything deeper than the limit will raise a
  warning and skip the entry. Set to `Infinity` to remove the
  limitation.
const DEFAULT_MAX_DEPTH = 1024
    // prevent excessively deep nesting of subfolders
    // set to `Infinity` to remove this restriction
    this.maxDepth = typeof opt.maxDepth === 'number'
      ? opt.maxDepth
      : DEFAULT_MAX_DEPTH

    const p = normPath(entry.path)
    const parts = p.split('/')

      parts.splice(0, this.strip)
      entry.path = parts.join('/')
    }

    if (isFinite(this.maxDepth) && parts.length > this.maxDepth) {
      this.warn('TAR_ENTRY_ERROR', 'path excessively deep', {
        entry,
        path: p,
        depth: parts.length,
        maxDepth: this.maxDepth,
      })
      return false
    t.match(warnings, [/^zlib: /])
const ReadEntry = require('../lib/read-entry.js')

t.test('excessively deep subfolder nesting', async t => {
  const tf = path.resolve(fixtures, 'excessively-deep.tar')
  const data = fs.readFileSync(tf)
  const warnings = []
  const onwarn = (c, w, { entry, path, depth, maxDepth }) =>
    warnings.push([c, w, { entry, path, depth, maxDepth }])

  const check = (t, maxDepth = 1024) => {
    t.match(warnings, [
      ['TAR_ENTRY_ERROR',
        'path excessively deep',
        {
          entry: ReadEntry,
          path: /^\.(\/a){1024,}\/foo.txt$/,
          depth: 222372,
          maxDepth,
        }
      ]
    ])
    warnings.length = 0
    t.end()
  }

  t.test('async', t => {
    const cwd = t.testdir()
    new Unpack({
      cwd,
      onwarn
    }).on('end', () => check(t)).end(data)
  })

  t.test('sync', t => {
    const cwd = t.testdir()
    new UnpackSync({
      cwd,
      onwarn
    }).end(data)
    check(t)
  })

  t.test('async set md', t => {
    const cwd = t.testdir()
    new Unpack({
      cwd,
      onwarn,
      maxDepth: 64,
    }).on('end', () => check(t, 64)).end(data)
  })

  t.test('sync set md', t => {
    const cwd = t.testdir()
    new UnpackSync({
      cwd,
      onwarn,
      maxDepth: 64,
    }).end(data)
    check(t, 64)
  })
})