Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
## 2025-02-14 - Replace execSync with execFileSync for Safe Execution
**Vulnerability:** The `execSync` function in `node:child_process` uses a shell by default, which can lead to command injection if input parameters are not properly sanitized. This was present in the `reconcile.ts` engine core and tests.
**Learning:** Even internal tooling or test environments require careful handling of shell executions to prevent unforeseen escalation vectors. `execFileSync` avoids invoking a shell by directly running the executable.
**Prevention:** Avoid string-based execution functions like `execSync`. Always use `execFileSync` (or `spawnSync`) with array-based arguments and specifically address the executable path, like `process.execPath`, to enforce execution safety.
6 changes: 3 additions & 3 deletions packages/core/src/loop.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { execSync } from "node:child_process";
import { execFileSync } from "node:child_process";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
Expand Down Expand Up @@ -173,10 +173,10 @@ describe("ledger benchmark e2e", () => {
it("reconcile passes validator for correct ledger implementation", () => {
const dir = setupWorkspace();
const mergeTarget = path.join(dir, "auth_service.js");
execSync(`node "${fixturePath("mock-dev-ledger.mjs")}" "${path.join(dir, "developer_output.json")}"`, {
execFileSync(process.execPath, [fixturePath("mock-dev-ledger.mjs"), path.join(dir, "developer_output.json")], {
stdio: "pipe",
});
execSync(`node "${fixturePath("mock-audit-pass.mjs")}" "${path.join(dir, "auditor_output.json")}"`, {
execFileSync(process.execPath, [fixturePath("mock-audit-pass.mjs"), path.join(dir, "auditor_output.json")], {
stdio: "pipe",
});

Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/reconcile.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { execSync } from "node:child_process";
import { execFileSync } from "node:child_process";
import crypto from "node:crypto";
import fs from "node:fs";
import path from "node:path";
Expand Down Expand Up @@ -139,7 +139,7 @@ export function reconcile(options: ReconcileOptions): ReconcileResult {
fs.writeFileSync(tempFile, extractedCode, "utf8");

try {
execSync(`node --check "${tempFile}"`, { stdio: "pipe" });
execFileSync(process.execPath, ["--check", tempFile], { stdio: "pipe" });
log.audit("Syntax check passed");
} catch (err) {
const stderr =
Expand Down
Loading