fix: Improve input handling in package scanner (#19147)

This commit is contained in:
Shireen Missi
2025-09-03 17:29:40 +01:00
committed by GitHub
parent a90584b6bc
commit c10da38719

View File

@@ -3,7 +3,7 @@
import fs from "fs"; import fs from "fs";
import path from "path"; import path from "path";
import { ESLint } from "eslint"; import { ESLint } from "eslint";
import { execSync } from "child_process"; import { spawnSync } from "child_process";
import tmp from "tmp"; import tmp from "tmp";
import semver from "semver"; import semver from "semver";
import axios from "axios"; import axios from "axios";
@@ -19,6 +19,11 @@ const TEMP_DIR = tmp.dirSync({ unsafeCleanup: true }).name;
const registry = "https://registry.npmjs.org/"; const registry = "https://registry.npmjs.org/";
export const resolvePackage = (packageSpec) => { export const resolvePackage = (packageSpec) => {
// Validate input to prevent command injection
if (!/^[a-zA-Z0-9@/_.-]+$/.test(packageSpec)) {
throw new Error('Invalid package specification');
}
let packageName, version; let packageName, version;
if (packageSpec.startsWith("@")) { if (packageSpec.startsWith("@")) {
if (packageSpec.includes("@", 1)) { if (packageSpec.includes("@", 1)) {
@@ -40,8 +45,14 @@ export const resolvePackage = (packageSpec) => {
const downloadAndExtractPackage = async (packageName, version) => { const downloadAndExtractPackage = async (packageName, version) => {
try { try {
// Download the tarball // Download the tarball using safe arguments
execSync(`npm -q pack ${packageName}@${version}`, { cwd: TEMP_DIR }); const npmResult = spawnSync('npm', ['-q', 'pack', `${packageName}@${version}`], {
cwd: TEMP_DIR,
stdio: 'pipe'
});
if (npmResult.status !== 0) {
throw new Error(`npm pack failed: ${npmResult.stderr?.toString()}`);
}
const tarballName = fs const tarballName = fs
.readdirSync(TEMP_DIR) .readdirSync(TEMP_DIR)
.find((file) => file.endsWith(".tgz")); .find((file) => file.endsWith(".tgz"));
@@ -52,9 +63,13 @@ const downloadAndExtractPackage = async (packageName, version) => {
// Unpack the tarball // Unpack the tarball
const packageDir = path.join(TEMP_DIR, `${packageName}-${version}`); const packageDir = path.join(TEMP_DIR, `${packageName}-${version}`);
fs.mkdirSync(packageDir, { recursive: true }); fs.mkdirSync(packageDir, { recursive: true });
execSync(`tar -xzf ${tarballName} -C ${packageDir} --strip-components=1`, { const tarResult = spawnSync('tar', ['-xzf', tarballName, '-C', packageDir, '--strip-components=1'], {
cwd: TEMP_DIR, cwd: TEMP_DIR,
stdio: 'pipe'
}); });
if (tarResult.status !== 0) {
throw new Error(`tar extraction failed: ${tarResult.stderr?.toString()}`);
}
fs.unlinkSync(path.join(TEMP_DIR, tarballName)); fs.unlinkSync(path.join(TEMP_DIR, tarballName));
return packageDir; return packageDir;