CVE-2022-21191 (JavaScript, published 2023-01-13T05:15Z)
Description: value: Versions of the package global-modules-path before 3.0.0 are vulnerable to Command Injection due to missing input sanitization or other checks and sandboxes being employed to the getPath  function.
Severity: nan (CVSS v3 base score: 9.8)
Weakness: NVD-CWE-Other \u2014 Other
NVD is only using a subset of CWE for mapping instead of the entire CWE, and the weakness type is not covered by that subset.
Repository: https://github.com/rosen-vladimirov/global-modules-path
Files changed:
lib/index.js
test/index.js
Commit message: fix: do not allow command injection

Due to usage of execSync, callers may inject commands, like getPath("something & touch abc", "somethingElse & touch def").
To fix this, replace execSync with spawnSync, which is safe for command injection.


Vulnerable code:
		const npmPrefixStdout = childProcess.execSync(`${pathToNpm} config get prefix`);
		const whereResult = (childProcess.execSync(`where ${executableName}`) || "").toString().split("\n");
		const whichResult = (childProcess.execSync(`which ${executableName}`) || "").toString().trim(),
			lsLResult = (childProcess.execSync(`ls -l \`which ${executableName}\``) || "").toString().trim();
const originalExecSync = childProcess.execSync;
		childProcess.execSync = originalExecSync;
					childProcess.execSync = (command) => {
						if (command.indexOf("get prefix") !== -1) {
							throw new Error(expectedErrorMessage);
					childProcess.execSync = (command) => {
					childProcess.execSync = () => null;
		childProcess.execSync = (command) => {
			if (command.indexOf("get prefix") !== -1) {
				return npmConfigPrefix;
				childProcess.execSync = (command) => {
					commands.push(command);
				childProcess.execSync = (command) => {
						throw new Error(expectedErrorMessage);
				childProcess.execSync = (command) => {
						return whereResult;
				childProcess.execSync = (command) => {
						return whereResult;
				childProcess.execSync = (command) => {
						return whereResult;
				childProcess.execSync = (command) => {
						return whereResult;
				childProcess.execSync = (command) => {
						return whereResult;
				childProcess.execSync = (command) => {
						return whereResult;
				childProcess.execSync = (command) => {
					commands.push(command);
					childProcess.execSync = (command) => {
					childProcess.execSync = (command) => {
						if (command.indexOf("ls -l") !== -1) {
							throw new Error(expectedErrorMessage);
						childProcess.execSync = (command) => {
							if (command.indexOf("ls -l") !== -1) {
								return lsLResult;
							if (command.indexOf("which") !== -1) {
								return whichResult;
						childProcess.execSync = (command) => {
							if (command.indexOf("ls -l") !== -1) {
								return lsLResult;
							if (command.indexOf("which") !== -1) {
								return whichResult;
						childProcess.execSync = (command) => {
							if (command.indexOf("ls -l") !== -1) {
								return lsLResult;
							if (command.indexOf("which") !== -1) {
								return whichResult;

Fixed code:
const spawnSyncWrapper = (command, commandArgs) => {
	const result = childProcess.spawnSync(command, commandArgs);
	if (!result) {
		return null;
	}

	if (result.error) {
		throw result.error;
	}

	if (result.stdout) {
		return result.stdout.toString().trim();
	}

	return null;
};

		const npmPrefixStdout = spawnSyncWrapper(pathToNpm, ["config", "get", "prefix"]);

		const whereResult = (spawnSyncWrapper("where", executableName) || "").split("\n");

		const whichResult = spawnSyncWrapper("which", [executableName]);
		const lsLResult = spawnSyncWrapper("ls", ["-l", whichResult]);
const originalspawnSync = childProcess.spawnSync;
		childProcess.spawnSync = originalspawnSync;
					childProcess.spawnSync = (command, commandArgs) => {
						if (commandArgs.indexOf("get") !== -1 && commandArgs.indexOf("prefix") !== -1) {
							return { error: new Error(expectedErrorMessage) };
					childProcess.spawnSync = (command) => {
					childProcess.spawnSync = () => null;
		fs.realpathSync = (p) => p; 
		childProcess.spawnSync = (command, commandArgs) => {
			if (commandArgs.indexOf("get") !== -1 && commandArgs.indexOf("prefix") !== -1) {
				return { stdout: npmConfigPrefix };
				childProcess.spawnSync = (command, commandArgs) => {
					commands.push(`${command} ${(commandArgs || []).join(" ")}`);
				childProcess.spawnSync = (command) => {
						return { error: new Error(expectedErrorMessage) };
				childProcess.spawnSync = (command) => {
						return { stdout: whereResult };
				childProcess.spawnSync = (command) => {
						return { stdout: whereResult };
				childProcess.spawnSync = (command) => {
						return { stdout: whereResult };
				childProcess.spawnSync = (command) => {
						return { stdout: whereResult };
				childProcess.spawnSync = (command) => {
						return { stdout: whereResult };
				childProcess.spawnSync = (command) => {
						return { stdout: whereResult };
				childProcess.spawnSync = (command, commandArgs) => {
					commands.push(`${command} ${(commandArgs || []).join(" ")}`);
					childProcess.spawnSync = (command) => {
					childProcess.spawnSync = (command) => {
						if (command === "ls") {
							return { error: new Error(expectedErrorMessage) };
						childProcess.spawnSync = (command) => {
							if (command === "ls") {
								return { stdout: lsLResult };
							if (command == "which") {
								return { stdout: whichResult };
						childProcess.spawnSync = (command) => {
							if (command === "ls") {
								return { stdout: lsLResult };
							if (command == "which") {
								return { stdout: whichResult };
						childProcess.spawnSync = (command) => {
							if (command === "ls") {
								return { stdout: lsLResult };
							if (command == "which") {
								return { stdout: whichResult };