diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000..ba2daab --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,7 @@ +## 2025-05-18 - Fix Command Injection in Reconciler + +**Vulnerability:** Found a command injection vulnerability in `packages/core/src/reconcile.ts` where `execSync` was used to execute a shell command constructed with a file path directly from the workspace. This means if a path contains shell metacharacters (e.g. `$`, \`, quotes), it could allow arbitrary command execution during the reconcile syntax check step. + +**Learning:** When executing a process using Node.js, relying on shell execution functions like `execSync` with strings that contain dynamic or user-controlled input can lead to command injection. + +**Prevention:** Use array-based argument passing functions like `spawnSync` along with `process.execPath` (to prevent executing arbitrary executables in `$PATH`) instead of string-based execution functions like `execSync`. diff --git a/packages/core/src/reconcile.ts b/packages/core/src/reconcile.ts index b0285bc..65c0a8f 100644 --- a/packages/core/src/reconcile.ts +++ b/packages/core/src/reconcile.ts @@ -1,4 +1,4 @@ -import { execSync } from "node:child_process"; +import { spawnSync } from "node:child_process"; import crypto from "node:crypto"; import fs from "node:fs"; import path from "node:path"; @@ -139,7 +139,8 @@ export function reconcile(options: ReconcileOptions): ReconcileResult { fs.writeFileSync(tempFile, extractedCode, "utf8"); try { - execSync(`node --check "${tempFile}"`, { stdio: "pipe" }); + const checkResult = spawnSync(process.execPath, ["--check", tempFile], { stdio: "pipe" }); + if (checkResult.error || checkResult.status !== 0) { throw checkResult.error || new Error((checkResult.stderr || "").toString()); } log.audit("Syntax check passed"); } catch (err) { const stderr =