Skip to content

fix: resolve symlink chains fully when extracting - #142

Merged
fengmk2 merged 1 commit into
1.xfrom
fix/symlink-chain-resolution-1.x
Aug 5, 2026
Merged

fix: resolve symlink chains fully when extracting#142
fengmk2 merged 1 commit into
1.xfrom
fix/symlink-chain-resolution-1.x

Conversation

@fengmk2

@fengmk2 fengmk2 commented Aug 5, 2026

Copy link
Copy Markdown
Member

Backport of #140 to 1.x.

isRealPathSafe() stopped walking as soon as realpath() failed on a dangling link, checking only that link's immediate target. A destination reached through several hops, or through a linked directory, was only partially resolved, so an entry could land somewhere the check had not accounted for.

It now resolves the remaining hops itself, bounded by MAX_SYMLINK_DEPTH, and walks from whichever extraction root actually contains the target so a link named in the real namespace is not rejected.

Behaviour change worth noting: a file entry landing on a symlink now replaces that link instead of writing through to whatever it points at. This matches tar(1), node-tar and libarchive. Where the platform has it, the write also opens with O_NOFOLLOW. Linked directories inside the extraction directory are still traversed.

Written in the callback style the surrounding 1.x code uses, so it stays compatible with the branch's Node range. Suite is 166 passing on this branch.

Backport of #140 to 1.x.

isRealPathSafe() stopped walking as soon as realpath() failed on a dangling
link, checking only that link's immediate target. A destination reached
through several hops, or through a linked directory, was only partially
resolved, so an entry could land somewhere the check had not accounted for.

Resolve the remaining hops by hand instead, bounded by MAX_SYMLINK_DEPTH, and
walk from whichever extraction root actually contains the target so a link
named in the real namespace is not rejected.

File entries no longer write through a symlink sitting at the destination.
The link is replaced by the entry, which is how tar(1), node-tar and
libarchive all behave. Where the platform has it, the write also opens with
O_NOFOLLOW.
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 70833fce-c5fa-41a4-a90e-4ee864feded8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@fengmk2
fengmk2 merged commit 90b2e54 into 1.x Aug 5, 2026
22 checks passed
@fengmk2
fengmk2 deleted the fix/symlink-chain-resolution-1.x branch August 5, 2026 12:46
fengmk2 pushed a commit that referenced this pull request Aug 5, 2026
[skip ci]

## <small>1.10.6 (2026-08-05)</small>

* fix: resolve symlink chains fully when extracting (#142) ([90b2e54](90b2e54)), closes [#142](#142) [#140](#140)
* chore: replace var with let/const in isRealPathSafe (#135) ([60fa3af](60fa3af)), closes [#135](#135)
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 1.10.6 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant