Skip to content

Commit 068aedc

Browse files
committed
fix(cp): improve symlink validation for cross-platform and relative paths
- Use path.posix.isAbsolute to detect Unix absolute paths on Windows - Replace overly restrictive '..' check with proper containment check - Resolve symlink target relative to symlink's parent directory - Handle root destination path as special case
1 parent 8485f40 commit 068aedc

File tree

1 file changed

+17
-2
lines changed

1 file changed

+17
-2
lines changed

src/lib/cp.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -411,11 +411,26 @@ export async function cpFromInstance(cfg: CpConfig, opts: CpFromInstanceOptions)
411411
}
412412
// Validate symlink target
413413
const linkTarget = currentHeader.link_target;
414-
if (path.isAbsolute(linkTarget) || path.normalize(linkTarget).startsWith('..')) {
415-
doReject(new Error(`Invalid symlink target: ${linkTarget}`));
414+
// Use path.posix.isAbsolute to detect Unix absolute paths even on Windows
415+
if (path.posix.isAbsolute(linkTarget) || path.isAbsolute(linkTarget)) {
416+
doReject(new Error(`Invalid symlink target (absolute path): ${linkTarget}`));
416417
ws.close();
417418
return;
418419
}
420+
// Check if the symlink target escapes the destination directory
421+
// Resolve relative to the symlink's parent directory
422+
const linkDir = path.dirname(targetPath);
423+
const resolvedTarget = path.resolve(linkDir, linkTarget);
424+
const dstPathNorm = path.resolve(opts.dstPath);
425+
// For root destination, just ensure resolved target is absolute
426+
// For other destinations, ensure resolved target is within dstPath
427+
if (dstPathNorm !== '/' && dstPathNorm !== path.sep) {
428+
if (!resolvedTarget.startsWith(dstPathNorm + path.sep) && resolvedTarget !== dstPathNorm) {
429+
doReject(new Error(`Invalid symlink target (escapes destination): ${linkTarget}`));
430+
ws.close();
431+
return;
432+
}
433+
}
419434
// Create parent directory if needed
420435
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
421436
try {

0 commit comments

Comments
 (0)