diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000..85cdc4c --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2023-10-25 - [Command Injection Risk] +**Vulnerability:** Use of `execSync` with a string interpolated path in `reconcile.ts` (`execSync(\`node --check "\${tempFile}"\`)`) opened up a command injection risk if the file path was ever attacker-controlled or contained quotes/shell metacharacters. +**Learning:** Even internal file paths (`path.join` with `options.workspace`) shouldn't be blindly trusted to shell execution (`execSync` or `spawn` with `shell: true`), as quotes or shell metacharacters could still technically cause escaping depending on OS path characteristics or upstream workspace configuration. +**Prevention:** Use `spawnSync` (or `spawn`) with an explicit argument array (`["--check", tempFile]`) and avoid shell execution. For Node scripts, invoke `process.execPath` explicitly instead of depending on `node` in the PATH string. diff --git a/packages/core/src/reconcile.ts b/packages/core/src/reconcile.ts index b0285bc..8ba29d2 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,10 @@ 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", encoding: "utf8" }); + if (checkResult.status !== 0) { + throw new Error(checkResult.stderr || checkResult.stdout || "Syntax check failed"); + } log.audit("Syntax check passed"); } catch (err) { const stderr =