fix(download): pass extract paths to PowerShell via env vars

Windows zip extraction interpolated archive/dest paths directly into the
PowerShell -Command string. A single quote in the path (e.g. a Windows
account like C:\Users\O'Brien) closed the string literal early, breaking
extraction and creating a code-injection shape. execFileSync guards the
OS-shell boundary but not the PowerShell interpreter inside.

Pass both paths via env vars ($env:CB_ARCHIVE / $env:CB_DEST) so
PowerShell reads them as data, never as code. No escaping needed.

Python wrapper unaffected (zipfile module + argv).
This commit is contained in:
CloakHQ
2026-06-20 02:19:48 +02:00
parent 39db492b04
commit 402a884088
+7 -2
View File
@@ -425,11 +425,16 @@ async function extractZip(archivePath: string, destDir: string): Promise<void> {
if (process.platform === "win32") {
// PowerShell 5.1's Expand-Archive uses .NET FileStream which can conflict
// with recently-closed Node.js file handles. Use ZipFile API directly.
// Pass paths via env vars (not interpolated into the script) so a quote or
// other special char in the path can't break out and be parsed as code.
execFileSync("powershell", [
"-NoProfile", "-Command",
`Add-Type -AssemblyName System.IO.Compression.FileSystem; ` +
`[System.IO.Compression.ZipFile]::ExtractToDirectory('${archivePath}', '${destDir}')`,
], { timeout: 120_000 });
`[System.IO.Compression.ZipFile]::ExtractToDirectory($env:CB_ARCHIVE, $env:CB_DEST)`,
], {
timeout: 120_000,
env: { ...process.env, CB_ARCHIVE: archivePath, CB_DEST: destDir },
});
} else {
execFileSync("unzip", ["-o", archivePath, "-d", destDir], { timeout: 120_000 });
}