Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/test/fixtures/zip-files/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const ZIP_CASES = [
{ name: "compressed-standard" },
{ name: "uncompressed" },
{ name: "zip-slip", wantErr: "a path outside of" },
{ name: "zip-slip-prefix", wantErr: "a path outside of" },
{ name: "zip64" },
].map(({ name, wantErr }) => ({
name,
Expand Down
Binary file not shown.
16 changes: 5 additions & 11 deletions src/unzip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,17 +124,11 @@ const extractEntriesFromBuffer = async (data: Buffer, outputDir: string): Promis
};

function isChildDir(parentDir: string, potentialChild: string): boolean {
try {
// 1. Resolve and normalize both paths to absolute paths
const resolvedParent = path.resolve(parentDir);
const resolvedChild = path.resolve(potentialChild);
// The child path must start with the parent path and not be the same path.
return resolvedChild.startsWith(resolvedParent) && resolvedChild !== resolvedParent;
} catch (error) {
// If either path does not exist, an error will be thrown.
// In this case, the potential child cannot be a subdirectory.
return false;
}
const resolvedParent = path.resolve(parentDir);
const resolvedChild = path.resolve(potentialChild);
const relative = path.relative(resolvedParent, resolvedChild);
// relative path must not escape the parent and must not be the parent itself
return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative);
}

export const unzip = async (inputPath: string, outputDir: string): Promise<void> => {
Expand Down