Skip to content

unpack: do not mutate cwd when extract strip empties a path - #465

Closed
dyk1454683243-sudo wants to merge 2 commits into
isaacs:mainfrom
dyk1454683243-sudo:cursor/fix-strip-existing-dir-perms-ebc7
Closed

dyk1454683243-sudo wants to merge 2 commits into
isaacs:mainfrom
dyk1454683243-sudo:cursor/fix-strip-existing-dir-perms-ebc7

Conversation

@dyk1454683243-sudo

@dyk1454683243-sudo dyk1454683243-sudo commented Sep 20, 2026 •

Copy link
Copy Markdown

Fixes #294

Problem

extract({ strip }) treated a fully-stripped directory entry as the extraction directory. As root (or with preserveOwner / chmod), that applied the archive member's uid/gid, mode, and mtime to an existing cwd.

GNU tar --strip-components skips members whose names become empty. It does not chown or chmod . in the reporter's reproduction:

mkdir dir
sudo chown 501 dir
tar -czf tarball.tgz dir
sudo tar --strip-components=1 -xzf tarball.tgz
# cwd owner unchanged

node-tar's equivalent tar.x({ file, strip: 1 }) changed cwd ownership to 501.

This matches the existing contract in TarOptions.strip ("any entry whose entire path is stripped will be excluded"), but dir and dir/ still resolved to cwd after parts.splice.

Fix

After applying strip, skip the entry when only empty / . segments remain. Remaining names (pkg/sub → sub) are still extracted, including metadata on existing remaining directories, which is what GNU tar -p --strip-components does.

Tests

test/unpack.js (strip does not mutate existing cwd (#294)):

  • dir-only archive with and without trailing slash (sync + async)
  • preserveOwner does not chown cwd
  • existing remaining dir still gets mode after strip
  • without strip, the directory entry is still extracted onto dir/ (cwd unchanged)
  • ./keepme after strip: 1 still extracts
  • strip: 2 on a/b/ does not mutate cwd
  • pre/. after strip: 1 does not mutate cwd

Discriminating check: the new tests fail on 2a22bfc (17 assertion failures) and pass on this branch.

Test plan

  • Reproduced against GNU tar 1.35 vs node-tar 7.5.22 (unfixed: cwd mode 755→700; as root, cwd uid→501)
  • After the fix, GNU tar and node-tar agree: cwd unchanged; remaining existing dirs still get metadata
  • sudo reproduction: cwd uid stays 1000 when archive dir is uid 501
  • npx tap test/unpack.js --disable-coverage -t0: 692/692 pass
  • New tests fail without the CHECKPATH skip and pass with it

cursoragent and others added 2 commits September 20, 2026 14:05
GNU tar --strip-components skips members whose names become empty.
node-tar applied those directory entries to cwd, so extract with
strip as root could change ownership, mode, and mtime of existing
directories. Fixes isaacs#294.

Co-authored-by: David <dyk1454683243-sudo@users.noreply.github.com>
Co-authored-by: David <dyk1454683243-sudo@users.noreply.github.com>
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.

[BUG] extract with strip can change permissions on existing files when running as root

3 participants