diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000..c6f87f2 --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2024-10-30 - Command Injection in Syntax Checker +**Vulnerability:** Use of string-based \`execSync\` for node syntax checking (\`execSync(\\\`node --check "\${tempFile}"\\\`)\`) allows for potential command injection if \`tempFile\` path can be manipulated. +**Learning:** Even internal tool execution or paths that seem controlled should use array-based argument passing (e.g., \`spawnSync\`) and \`process.execPath\` to absolutely prevent injection vulnerabilities in execution engines. +**Prevention:** Always prefer \`spawnSync\` over \`execSync\`, use \`process.execPath\` for invoking node, and pass arguments as an array rather than constructing a command string. diff --git a/packages/core/src/reconcile.ts b/packages/core/src/reconcile.ts index b0285bc..482624f 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,13 @@ export function reconcile(options: ReconcileOptions): ReconcileResult { fs.writeFileSync(tempFile, extractedCode, "utf8"); try { - execSync(`node --check "${tempFile}"`, { stdio: "pipe" }); + const result = spawnSync(process.execPath, ["--check", tempFile], { stdio: "pipe" }); + if (result.error) throw result.error; + if (result.status !== 0) { + const err = new Error("Syntax check failed") as Error & { stderr: Buffer }; + err.stderr = result.stderr; + throw err; + } log.audit("Syntax check passed"); } catch (err) { const stderr =