fix(security): resolve CodeQL findings in package.mjs build script

TOCTOU (CWE-367): fs.statSync(entry.from).isDirectory() was called
before mirrorDirectory/cpSync without error handling. If the path
disappears between stat and use, the subsequent operation throws
unhandled. Wrap in try/catch and continue on error.

Indirect uncontrolled command line (CWE-78): appBuilderLibVersion is
read from desktopPackageLock (an external file) and embedded directly
in an npm pack CLI argument. Validate it matches a semver pattern
before use to prevent injection via a compromised lockfile.
This commit is contained in:
Sparsh 2026-05-19 00:58:09 +05:30
parent 377a96ffd5
commit b9b3ec6a63

View file

@ -36,6 +36,12 @@ const requiredBuilderRuntimeModules = ['app-builder-bin'];
const appBuilderLibVersion =
desktopPackageLock.packages?.['node_modules/app-builder-lib']?.version ??
electronBuilderVersion.replace(/^[^\d]*/, '');
// Validate version is safe semver before embedding in a CLI argument.
if (!/^\d+\.\d+\.\d+(?:[.-][a-zA-Z0-9._-]*)?$/.test(appBuilderLibVersion)) {
throw new Error(
`Invalid app-builder-lib version in lockfile: ${JSON.stringify(appBuilderLibVersion)}`,
);
}
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
const outputDir = path.join(releaseRoot, stamp);
const latestReleasePointerPath = path.join(releaseRoot, '.latest-unpacked-release');
@ -279,7 +285,14 @@ const syncPackagedRuntimeResources = () => {
for (const entry of packagedResourceEntries) {
const destinationPath = path.join(resourceRoot, entry.to);
if (fs.statSync(entry.from).isDirectory()) {
let isDirectory;
try {
isDirectory = fs.statSync(entry.from).isDirectory();
} catch (err) {
if (err.code !== 'ENOENT') throw err;
continue;
}
if (isDirectory) {
mirrorDirectory(entry.from, destinationPath);
continue;
}