Skip to content

Bump transitive node-tar to 7.5.16 to remediate GHSA-vmf3-w455-68vh#2012

Closed
mikeharder with Copilot wants to merge 2 commits into
mainfrom
copilot/fix-node-tar-vulnerability
Closed

Bump transitive node-tar to 7.5.16 to remediate GHSA-vmf3-w455-68vh#2012
mikeharder with Copilot wants to merge 2 commits into
mainfrom
copilot/fix-node-tar-vulnerability

Conversation

Copilot AI commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

tar@7.5.13 in the workspace lockfile is vulnerable to a PAX/GNU header parsing differential that can cause archive interpretation conflicts (CVE-2026-53655). This change pins the dependency graph to the minimum patched version, tar@7.5.16, with no direct code-path changes.

  • Dependency remediation

    • Added workspace-level pnpm override for tar in pnpm-workspace.yaml (the effective override location under pnpm v10 in this repo).
    • Regenerated pnpm-lock.yaml so all resolved tar entries move from 7.5.13 to 7.5.16.
  • Reachability assessment

    • Searched repository sources for node-tar API usage (tar.list, tar.extract/tar.x, tar.Parse, tar.Unpack, direct tar imports/requires).
    • No direct call sites were found; exposure is transitive via toolchain dependencies, so this is primarily dependency-risk remediation.
# pnpm-workspace.yaml
overrides:
  tar: 7.5.16
Original prompt

This section details the Dependabot vulnerability alert you should resolve

<alert_title>node-tar applies PAX size override to intermediary GNU long-name/long-link headers, causing tar parser interpretation differential (file smuggling)</alert_title>
<alert_description>### Summary

tar (node-tar) applies a PAX extended header's size= record (and other PAX
overrides) to the next header entry of any type, including intermediary
metadata headers such as a GNU long-name (L) or long-link (K) entry. Per
POSIX pax, a PAX extended header (x) describes the next file entry, not the
intermediary extension headers that may sit between the x header and the file
it annotates. Because node-tar lets the PAX size override the byte length of
an intervening L/K/x header, an attacker can desynchronize node-tar's
stream cursor relative to every other mainstream tar implementation
(GNU tar, libarchive/bsdtar, Python tarfile, and the now-fixed tar-rs /
astral-tokio-tar).

The result is a tar parser interpretation differential (CWE-436): a single
crafted archive yields a different set of members under node-tar than under the
reference tar tools. An attacker can use this to hide a member from one parser
while it is visible to another, which defeats security tooling whose scanner and
extractor disagree on archive contents (e.g. a malware/secret scanner that lists
entries with one library while a downstream step extracts with another). node-tar
is one of the most widely deployed JavaScript tar libraries (it backs npm's own
package-tarball handling and is a transitive dependency of a very large fraction
of the npm ecosystem), so the blast radius for "files that extract differently
depending on the tool" is broad.

This is the same root cause and fix that was just addressed upstream in the Rust
tar ecosystem (tar-rs / astral-tokio-tar); node-tar carries the equivalent
defect and has no equivalent guard.

Impact

  • CWE-436 Interpretation Conflict / inconsistent tar parsing (the same class as
    the prior tar "smuggling" advisories GHSA-j5gw-2vrg-8fgx and
    GHSA-fp55-jw48-c537).
  • A crafted archive can present one logical member list to a tool that lists or
    scans with node-tar and a different member list to GNU tar / libarchive /
    Python tarfile (and vice versa). This lets a malicious file be hidden from a
    scanner that uses a different parser than the eventual extractor, or hidden
    from node-tar-based inspection while still landing on disk via a system tar.
  • No authentication is required; the only precondition is that a victim parses
    an attacker-supplied tar with node-tar. Tar archives are routinely fetched
    from untrusted sources (package registries, user uploads, CI artifacts,
    container layers).
  • Severity: Medium. Impact is integrity-of-archive-interpretation, not direct
    RCE; it is a building block for supply-chain / scanner-evasion attacks rather
    than a standalone code-execution primitive.

Vulnerable code (file:line)

src/header.ts (compiled to dist/esm/header.js:49 and
dist/commonjs/header.js:85 in the published tar@7.5.15):

// Header.decode(buf, off, ex, gex)
this.size = ex?.size ?? gex?.size ?? decNumber(buf, off + 124, 12)

ex is the currently-accumulated PAX local extended header and gex the
PAX global header. The size override from ex/gex is applied
unconditionally to whatever header is being decoded next — there is no check
that the header being decoded is a real file entry rather than an intermediary
extension header.

src/parse.ts, [CONSUMEHEADER] constructs the next header with the current
EX/GEX applied:

const header = new Header(chunk, position, this[EX], this[GEX])

and later branches on whether that header is a metadata entry. this[EX] is
cleared only in the non-meta (real file) branch:

if (entry.meta) {
  // L / K / x / g metadata entries: this[EX] is left intact here
  if (entry.size > this.maxMetaEntrySize) {
    entry.ignore = true
    this[STATE] = 'ignore'
    entry.resume()
  } else if (entry.size > 0) {
    this[META] = ''
    entry.on('data', c => (this[META] += c))
    this[STATE] = 'meta'
  }
} else {
  this[EX] = undefined   // EX cleared only once a real file entry is reached
}

When the stream is ordered x (PAX, size=N) -> L (GNU long-name) -> file, the
L header is constructed with this[EX] still set, so its size/remain
becomes N instead of the L payload's true length. node-tar then consumes N
bytes of "metadata" and resumes header parsing at the wrong offset, landing
mid-stream. Every other mainstream parser applies the PAX size only to the
following file entry, so they stay synchronized.

The correct behavior (and the fix shipped upstream in the Rust tar ecosystem) is
to not apply PAX size/overrides when the entry being decoded is itself an
extension header (L GNU long-name, K GNU long-link, x PAX local, g PAX
global).

##...

Copilot AI changed the title [WIP] Fix node-tar PAX size override vulnerability Bump transitive node-tar to 7.5.16 to remediate GHSA-vmf3-w455-68vh Jun 24, 2026
Copilot AI requested a review from mikeharder June 24, 2026 06:16
@mikeharder mikeharder closed this Jul 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants