diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 2370299323..ceb05c7376 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -1,4 +1,12 @@ -## 2024-05-24 - Weak Hashing Algorithm (SHA256 without salt) - **Vulnerability:** The codebase was obfuscating credentials and tokens using SHA-256 without a salt. These hashes were stored and used for state integrity checks and multi-sandbox conflict detection. - **Learning:** Pure string equality checks on hashes (`a === b`) for deterministic validation creates an implicit requirement for saltless, fast algorithms which naturally leads to weak hashing implementations. - **Prevention:** For secure operations, prefer Node.js built-ins (`scryptSync` + `timingSafeEqual`). When deterministic state comparison is necessary, it must not apply to secrets; secrets should always use randomized salts and dedicated verification routines. +## 2025-02-27 - Command Injection in docker pull + +**Vulnerability:** In `src/lib/inference/vllm.ts`, the `pullImage` function was susceptible to command injection because the `profile.image` value was directly interpolated into a shell string executed via `runShell`. An attacker who could control `profile.image` could inject arbitrary shell commands. + +**Learning:** When invoking external commands like `docker`, one should prefer spawning the command directly with its arguments in an array instead of concatenating them into a shell string. + +**Prevention:** Use `run` instead of `runShell` where possible, taking advantage of the argv array parameter. Avoid passing un-sanitized user input into strings executed via the shell. + +## 2026-05-29 - [Sandbox SSH Command Injection] +**Vulnerability:** Shell Command Injection via interpolation in `spawnSync('ssh')` when clearing sandbox state directories. +**Learning:** `shellQuote` and shell array expansions can be unreliable when passed through SSH command boundaries, leading to potential RCE if filenames are attacker-controlled. +**Prevention:** Avoid shell string interpolation for dynamic lists. Pass arguments as null-terminated strings via `stdin` to remote `xargs -0` for deterministic, un-interpolated execution. diff --git a/src/lib/state/sandbox.ts b/src/lib/state/sandbox.ts index d5e48516db..ce797476c3 100644 --- a/src/lib/state/sandbox.ts +++ b/src/lib/state/sandbox.ts @@ -1208,10 +1208,12 @@ function restoreStateDirs( // Remove existing state dirs before extracting so stale files from // later snapshots don't persist after restoring an earlier one. - const rmCmd = localDirs.map((d) => `rm -rf -- ${shellQuote(`${dir}/${d}`)}`).join(" && "); - _log(`Cleaning target dirs before restore: ${rmCmd}`); + const rmCmd = "xargs -0 rm -rf --"; + const rmInput = localDirs.map((d) => `${dir}/${d}`).join("\0"); + _log(`Cleaning target dirs before restore via xargs null-terminated pipe`); const rmResult = spawnSync("ssh", [...sshArgs(configFile, sandboxName), rmCmd], { - stdio: ["ignore", "pipe", "pipe"], + input: rmInput, + stdio: ["pipe", "pipe", "pipe"], timeout: 30000, }); if (rmResult.status !== 0 || rmResult.error || rmResult.signal) {