From fb35635c103f7994c9ab98dd782bdb832ecccfd2 Mon Sep 17 00:00:00 2001 From: mahanandhi <46371575+mahanandhi@users.noreply.github.com> Date: Thu, 19 Feb 2026 03:19:09 -0800 Subject: [PATCH] Security: use execFileSync instead of execSync with shell strings (#20655) Replace execSync (which spawns a shell) with execFileSync (which invokes the binary directly with an argv array). This eliminates command injection risk from interpolated arguments. Co-authored-by: sirishacyd Co-authored-by: Claude Opus 4.6 --- src/agents/date-time.ts | 10 ++++++---- src/daemon/program-args.ts | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/agents/date-time.ts b/src/agents/date-time.ts index dde0788de2..8d5f537212 100644 --- a/src/agents/date-time.ts +++ b/src/agents/date-time.ts @@ -1,4 +1,4 @@ -import { execSync } from "node:child_process"; +import { execFileSync } from "node:child_process"; export type TimeFormatPreference = "auto" | "12" | "24"; export type ResolvedTimeFormat = "12" | "24"; @@ -96,9 +96,10 @@ export function withNormalizedTimestamp>( function detectSystemTimeFormat(): boolean { if (process.platform === "darwin") { try { - const result = execSync("defaults read -g AppleICUForce24HourTime 2>/dev/null", { + const result = execFileSync("defaults", ["read", "-g", "AppleICUForce24HourTime"], { encoding: "utf8", timeout: 500, + stdio: ["pipe", "pipe", "pipe"], }).trim(); if (result === "1") { return true; @@ -113,8 +114,9 @@ function detectSystemTimeFormat(): boolean { if (process.platform === "win32") { try { - const result = execSync( - 'powershell -Command "(Get-Culture).DateTimeFormat.ShortTimePattern"', + const result = execFileSync( + "powershell", + ["-Command", "(Get-Culture).DateTimeFormat.ShortTimePattern"], { encoding: "utf8", timeout: 1000 }, ).trim(); if (result.startsWith("H")) { diff --git a/src/daemon/program-args.ts b/src/daemon/program-args.ts index 0e3c903987..102d547c79 100644 --- a/src/daemon/program-args.ts +++ b/src/daemon/program-args.ts @@ -148,10 +148,10 @@ async function resolveNodePath(): Promise { } async function resolveBinaryPath(binary: string): Promise { - const { execSync } = await import("node:child_process"); + const { execFileSync } = await import("node:child_process"); const cmd = process.platform === "win32" ? "where" : "which"; try { - const output = execSync(`${cmd} ${binary}`, { encoding: "utf8" }).trim(); + const output = execFileSync(cmd, [binary], { encoding: "utf8" }).trim(); const resolved = output.split(/\r?\n/)[0]?.trim(); if (!resolved) { throw new Error("empty");