Fix extract path traversal check#355
Open
GaneshVG18 wants to merge 1 commit into
Open
Conversation
|
The same Verified independently — both code paths are exploitable with the same PoC: // Works with both Extract() and Open.file().then(d => d.extract())
const zip = new JSZip();
zip.file('../out-evil/pwned.txt', 'escaped');
// extract to /tmp/out → file appears at /tmp/out-evil/pwned.txt
const extractPath = path.join(opts.path, entry.path);
if (extractPath.indexOf(opts.path) != 0) {
return;
}Needs the same |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
path.resolve()andpath.relative().Root cause
Extract()usedextractPath.indexOf(opts.path) != 0to decide whether a zip entry stayed inside the destination directory. That is string-prefix matching, so a resolved target such as/tmp/extractEvil/hacked.txtcan pass when the intended destination is/tmp/extract.Fix
The new check resolves the destination path and entry target, computes the relative path from destination to target, and skips entries that resolve outside the destination (
..or absolute relative paths).Fixes #353.
Verification
npx eslint lib/extract.js test/uncompressed.jsnpx tap test/uncompressed.js --no-coverage --reporter=specnpx tap $(find test -name '*.js' ! -name 'openS3.js' ! -name 'openS3_v3.js' | sort) --no-coverage --reporter=dotgit diff --checkNote: full
npm testreaches the S3 v3 integration test and fails locally because AWS credentials are not configured.