From d8669be1efc8ee026b2c5ca2f29e52dd33fb6ed2 Mon Sep 17 00:00:00 2001 From: "luke.swan" Date: Wed, 16 Oct 2024 12:48:28 +0300 Subject: [PATCH 1/2] Sanitize spawn calls which contain .cmd for win32 See https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2 Code style fixes --- src/index.ts | 1 + src/package-managers/npm.ts | 7 +++++-- src/package-managers/pnpm.ts | 9 ++++++--- src/package-managers/yarn.ts | 7 +++++-- src/types/SpawnOptions.ts | 1 + 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/index.ts b/src/index.ts index bf7a7620..7e2d0a82 100755 --- a/src/index.ts +++ b/src/index.ts @@ -174,6 +174,7 @@ const install = async ( // See: https://github.com/raineorshine/npm-check-updates/issues/1191 ...(packageManager === 'pnpm' ? { npm_config_strict_peer_dependencies: false } : null), }, + shell: process.platform === 'win32', }, ) print(options, stdout) diff --git a/src/package-managers/npm.ts b/src/package-managers/npm.ts index 910775d1..719a18f3 100644 --- a/src/package-managers/npm.ts +++ b/src/package-managers/npm.ts @@ -586,6 +586,7 @@ async function spawnNpm( spawnOptions: Index = {}, ): Promise { const cmd = process.platform === 'win32' ? 'npm.cmd' : 'npm' + const sanitizedSpawnOptions = process.platform === 'win32' ? { ...spawnOptions, shell: true } : spawnOptions const fullArgs = [ ...(npmOptions.global ? [`--global`] : []), @@ -593,7 +594,7 @@ async function spawnNpm( '--json', ...(Array.isArray(args) ? args : [args]), ] - const { stdout } = await spawn(cmd, fullArgs, spawnPleaseOptions, spawnOptions) + const { stdout } = await spawn(cmd, fullArgs, spawnPleaseOptions, sanitizedSpawnOptions) return stdout } @@ -609,15 +610,17 @@ export async function defaultPrefix(options: Options): Promise getInstalledPackages if (!options.global) return npm.list(options) + const spawnOptions = {} const cmd = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm' - const { stdout } = await spawn(cmd, ['ls', '-g', '--json']) + const sanitzedSpawnOptions = process.platform === 'win32' ? { ...spawnOptions, shell: true } : spawnOptions + const { stdout } = await spawn(cmd, ['ls', '-g', '--json'], {}, sanitzedSpawnOptions) const result = JSON.parse(stdout) as PnpmList const list = keyValueBy(result[0].dependencies || {}, (name, { version }) => ({ [name]: version, @@ -91,10 +93,11 @@ export const semver = withNpmWorkspaceConfig(npm.semver) async function spawnPnpm( args: string | string[], npmOptions: NpmOptions = {}, - spawnOptions?: SpawnOptions, + spawnOptions: SpawnOptions = {}, spawnPleaseOptions?: SpawnPleaseOptions, ): Promise { const cmd = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm' + const sanitzedSpawnOptions = process.platform === 'win32' ? { ...spawnOptions, shell: true } : spawnOptions const fullArgs = [ ...(npmOptions.global ? 'global' : []), @@ -102,7 +105,7 @@ async function spawnPnpm( ...(npmOptions.prefix ? `--prefix=${npmOptions.prefix}` : []), ] - const { stdout } = await spawn(cmd, fullArgs, spawnPleaseOptions, spawnOptions) + const { stdout } = await spawn(cmd, fullArgs, spawnPleaseOptions, sanitzedSpawnOptions) return stdout } diff --git a/src/package-managers/yarn.ts b/src/package-managers/yarn.ts index e27b864d..40029a67 100644 --- a/src/package-managers/yarn.ts +++ b/src/package-managers/yarn.ts @@ -196,6 +196,7 @@ async function spawnYarn( spawnOptions: SpawnOptions = {}, ): Promise { const cmd = process.platform === 'win32' ? 'yarn.cmd' : 'yarn' + const sanitizedSpawnOptions = process.platform === 'win32' ? { ...spawnOptions, shell: true } : spawnOptions const fullArgs = [ ...(yarnOptions.global ? ['global'] : []), @@ -208,7 +209,7 @@ async function spawnYarn( ...(Array.isArray(args) ? args : [args]), ] - const { stdout } = await spawn(cmd, fullArgs, spawnPleaseOptions, spawnOptions) + const { stdout } = await spawn(cmd, fullArgs, spawnPleaseOptions, sanitizedSpawnOptions) return stdout } @@ -225,10 +226,12 @@ export async function defaultPrefix(options: Options): Promise { if (options.prefix) { return Promise.resolve(options.prefix) } + const spawnOptions = {} const cmd = process.platform === 'win32' ? 'yarn.cmd' : 'yarn' + const sanitizedSpawnOptions = process.platform === 'win32' ? { ...spawnOptions, shell: true } : spawnOptions - const { stdout: prefix } = await spawn(cmd, ['global', 'dir']) + const { stdout: prefix } = await spawn(cmd, ['global', 'dir'], {}, sanitizedSpawnOptions) // yarn 2.0 does not support yarn global // catch error to prevent process from crashing // https://github.com/raineorshine/npm-check-updates/issues/873 diff --git a/src/types/SpawnOptions.ts b/src/types/SpawnOptions.ts index fff99f8c..a47401c0 100644 --- a/src/types/SpawnOptions.ts +++ b/src/types/SpawnOptions.ts @@ -4,4 +4,5 @@ import { Index } from './IndexType' export interface SpawnOptions { cwd?: string env?: Index + shell?: boolean } From 2c87809c0c0c27a100b46030b1bc84ed5ac99bd8 Mon Sep 17 00:00:00 2001 From: Luke Swan Date: Wed, 16 Oct 2024 23:33:15 +0300 Subject: [PATCH 2/2] Revert sanitization in spawn calls --- src/package-managers/npm.ts | 3 +-- src/package-managers/yarn.ts | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/package-managers/npm.ts b/src/package-managers/npm.ts index 719a18f3..ee0a0079 100644 --- a/src/package-managers/npm.ts +++ b/src/package-managers/npm.ts @@ -586,7 +586,6 @@ async function spawnNpm( spawnOptions: Index = {}, ): Promise { const cmd = process.platform === 'win32' ? 'npm.cmd' : 'npm' - const sanitizedSpawnOptions = process.platform === 'win32' ? { ...spawnOptions, shell: true } : spawnOptions const fullArgs = [ ...(npmOptions.global ? [`--global`] : []), @@ -594,7 +593,7 @@ async function spawnNpm( '--json', ...(Array.isArray(args) ? args : [args]), ] - const { stdout } = await spawn(cmd, fullArgs, spawnPleaseOptions, sanitizedSpawnOptions) + const { stdout } = await spawn(cmd, fullArgs, spawnPleaseOptions, spawnOptions) return stdout } diff --git a/src/package-managers/yarn.ts b/src/package-managers/yarn.ts index 40029a67..bb9db2f9 100644 --- a/src/package-managers/yarn.ts +++ b/src/package-managers/yarn.ts @@ -196,7 +196,6 @@ async function spawnYarn( spawnOptions: SpawnOptions = {}, ): Promise { const cmd = process.platform === 'win32' ? 'yarn.cmd' : 'yarn' - const sanitizedSpawnOptions = process.platform === 'win32' ? { ...spawnOptions, shell: true } : spawnOptions const fullArgs = [ ...(yarnOptions.global ? ['global'] : []), @@ -209,7 +208,7 @@ async function spawnYarn( ...(Array.isArray(args) ? args : [args]), ] - const { stdout } = await spawn(cmd, fullArgs, spawnPleaseOptions, sanitizedSpawnOptions) + const { stdout } = await spawn(cmd, fullArgs, spawnPleaseOptions, spawnOptions) return stdout }