From d619ab878f98b6f0e5e3a3b92b3df67bf83b6982 Mon Sep 17 00:00:00 2001 From: Joe Hanley Date: Wed, 8 Oct 2025 10:55:11 -0700 Subject: [PATCH 1/2] Stop following symlinks when archiving directories --- src/archiveDirectory.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/archiveDirectory.ts b/src/archiveDirectory.ts index cbcadd992b3..9f6c65d3b9d 100644 --- a/src/archiveDirectory.ts +++ b/src/archiveDirectory.ts @@ -100,7 +100,7 @@ async function tarDirectory( gzip: true, file: tempFile.name, cwd: sourceDirectory, - follow: true, + follow: false, noDirRecurse: true, portable: true, }, @@ -141,7 +141,14 @@ async function zipDirectory( } throw err; } - for (const file of files) { + // For security, filter out all symlinks + const realFiles = await Promise.all( + files.filter(async (f) => { + const stats = await fs.promises.lstat(f.name); + return !stats.isSymbolicLink(); + }), + ); + for (const file of realFiles) { const name = path.relative(sourceDirectory, file.name); allFiles.push(name); archive.file(file.name, { From 2c6a2b1daf9a951d94a54f31b019cb774bb72ff7 Mon Sep 17 00:00:00 2001 From: Thomas Bouldin Date: Mon, 13 Oct 2025 11:02:06 -0700 Subject: [PATCH 2/2] Update exfil PR (#9289) * Fix filter for symlinks * Fine. Preserve ordering at the cost of readability --- src/archiveDirectory.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/archiveDirectory.ts b/src/archiveDirectory.ts index 9f6c65d3b9d..21dc7aee002 100644 --- a/src/archiveDirectory.ts +++ b/src/archiveDirectory.ts @@ -141,13 +141,14 @@ async function zipDirectory( } throw err; } - // For security, filter out all symlinks - const realFiles = await Promise.all( - files.filter(async (f) => { + // For security, filter out all symlinks. This code is a bit obtuse to preserve ordering. + const realFiles = (await Promise.all( + files.map(async (f) => { const stats = await fs.promises.lstat(f.name); - return !stats.isSymbolicLink(); + return stats.isSymbolicLink() ? null : f; }), - ); + )).filter((fileOrNull): fileOrNull is typeof files[number] => fileOrNull !== null); + for (const file of realFiles) { const name = path.relative(sourceDirectory, file.name); allFiles.push(name);