From 4c7cf5639030b394337f21ded6afecea7c84ce3d Mon Sep 17 00:00:00 2001 From: Xelson431 Date: Mon, 4 May 2026 21:35:36 +0100 Subject: [PATCH] fix: prevent shell commands from killing all Node.js processes OpenCode is built on Node.js (node.exe). Running commands like 'taskkill /F /IM node.exe', 'killall node', 'pkill node', or 'Get-Process node | Stop-Process' crashes the AI assistant itself. This change adds defense in depth: 1. System prompt guard: Injects a critical safety reminder into the environment prompt for all models, instructing the AI never to run broad Node process-killing commands. 2. Shell tool prompt guard: Adds the same safety rule to the bash/shell tool description so the AI sees it every time the tool is invoked. 3. Runtime command guard: Validates shell commands before execution in ShellTool and throws a clear error if a dangerous pattern is detected. Fixes the immediate crash vector while keeping legitimate per-PID kills and project-scoped stop commands (npm stop, pm2 stop) allowed. --- packages/opencode/src/session/system.ts | 6 ++++++ packages/opencode/src/tool/shell.ts | 17 +++++++++++++++++ packages/opencode/src/tool/shell/shell.txt | 6 ++++++ 3 files changed, 29 insertions(+) diff --git a/packages/opencode/src/session/system.ts b/packages/opencode/src/session/system.ts index 06c71fa7dbdd..e5dad5401c85 100644 --- a/packages/opencode/src/session/system.ts +++ b/packages/opencode/src/session/system.ts @@ -58,6 +58,12 @@ export const layer = Layer.effect( ` Platform: ${process.platform}`, ` Today's date: ${new Date().toDateString()}`, ``, + ``, + `## System Safety (Critical)`, + ``, + `- **NEVER** run commands that kill all Node.js processes (e.g., \`taskkill /F /IM node.exe\`, \`killall node\`, \`pkill node\`, \`Get-Process node | Stop-Process\`, etc.).`, + `- OpenCode is built on Node.js (\`node.exe\`). Killing all Node processes will immediately crash the AI assistant and terminate the current session.`, + `- If you need to stop a specific process, target it by PID or use process-manager commands scoped to the project (e.g., \`npm stop\`, \`pm2 stop \`).`, ].join("\n"), ] }), diff --git a/packages/opencode/src/tool/shell.ts b/packages/opencode/src/tool/shell.ts index d3ca542684de..46c56ed858a4 100644 --- a/packages/opencode/src/tool/shell.ts +++ b/packages/opencode/src/tool/shell.ts @@ -28,6 +28,18 @@ export { Parameters } from "./shell/prompt" const MAX_METADATA_LENGTH = 30_000 const DEFAULT_TIMEOUT = Flag.OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS || 2 * 60 * 1000 const CWD = new Set(["cd", "chdir", "popd", "pushd", "push-location", "set-location"]) + +const DANGEROUS_COMMAND_PATTERNS = [ + /taskkill\s+.*\/?[Ff]\s+.*\/?[Ii][Mm]\s+node\.?exe/i, + /taskkill\s+.*\/?[Ii][Mm]\s+node\.?exe/i, + /killall\s+node/i, + /pkill\s+node/i, + /Get-Process\s+.*node\s*\|\s*Stop-Process/i, +] + +function isDangerousCommand(command: string): boolean { + return DANGEROUS_COMMAND_PATTERNS.some((pattern) => pattern.test(command)) +} const FILES = new Set([ ...CWD, "rm", @@ -601,6 +613,11 @@ export const ShellTool = Tool.define( throw new Error(`Invalid timeout value: ${params.timeout}. Timeout must be a positive number.`) } const timeout = params.timeout ?? DEFAULT_TIMEOUT + if (isDangerousCommand(params.command)) { + throw new Error( + `Command blocked for system safety: "${params.command}". This command would kill all Node.js processes, which crashes OpenCode because it is built on Node.js (node.exe). If you need to stop a specific process, target it by PID or use project-scoped commands like "npm stop" or "pm2 stop ".`, + ) + } const ps = Shell.ps(shell) yield* Effect.scoped( Effect.gen(function* () { diff --git a/packages/opencode/src/tool/shell/shell.txt b/packages/opencode/src/tool/shell/shell.txt index 5cba07805c1e..ca9837efdf43 100644 --- a/packages/opencode/src/tool/shell/shell.txt +++ b/packages/opencode/src/tool/shell/shell.txt @@ -8,6 +8,12 @@ Use `${tmp}` for temporary work outside the workspace. This directory has alread IMPORTANT: This tool is for terminal operations like git, npm, docker, etc. DO NOT use it for file operations (reading, writing, editing, searching, finding files) - use the specialized tools for this instead. +## System Safety (Critical) + +- **NEVER** run commands that kill all Node.js processes (e.g., `taskkill /F /IM node.exe`, `killall node`, `pkill node`, `Get-Process node | Stop-Process`, etc.). +- OpenCode is built on Node.js (`node.exe`). Killing all Node processes will immediately crash the AI assistant and terminate the current session. +- If you need to stop a specific process, target it by PID or use process-manager commands scoped to the project (e.g., `npm stop`, `pm2 stop `). + ${commandSection} # Committing changes with git