T09 · Insecure Skill Coding Practices
Error
- Location
- handler.js:10
- Finding
- Shell Injection Allows Command Execution Outside the Intended tmux Session<![CDATA[ ## Vulnerability Details **File Location**: `handler.js`, lines 10–13 **Vulnerability Type**: OS command injection through unsafe shell-string construction **Risk Level**: High ### Vulnerable Code ```javascript function sendCommand(cmd) { const escaped = cmd.replace(/"/g, '\\"'); execSync(`tmux send-keys -t claw "${escaped}" C-m`); } ``` ### Technical Analysis The attacker-controlled `cmd` value is interpolated into a command string passed to `execSync()`. Node.js executes this string through a system shell. Escaping only double quotation marks does not neutralize shell syntax that remains active inside a double-quoted shell argument. In particular, command substitutions using `$(...)` or backticks are evaluated by the parent shell before `tmux` receives the text. Consequently, an input intended to be typed inside tmux can cause an additional command to execute directly in the Skill handler's process context. This violates the documented security boundary that commands are always run inside tmux session `claw`. ### Attack Path 1. An attacker or untrusted caller supplies a command containing shell substitution, for example: ```text echo $(id > /tmp/claw-shell-proof) ``` 2. `isDangerous()` does not reject the input because it contains none of the denylisted strings. 3. `sendCommand()` interpolates the input into the shell command: ```text tmux send-keys -t claw "echo $(id > /tmp/claw-shell-proof)" C-m ``` 4. The shell launched by `execSync()` evaluates `$(id > /tmp/claw-shell-proof)` before invoking `tmux`. 5. The injected `id` command therefore runs outside tmux with the identity and permissions of the Skill process. 6. Only the resulting substituted text is passed to the tmux pane, which can make the out-of-session execution less apparent in captured output. ### Impact Assessment An attacker can execute arbitrary shell commands in the host context of the Skill handler rather than only inside the designated tmux ses ...[truncated 495 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Avoid invoking a shell when passing attacker-controlled command text to `tmux`. Use an API that accepts the executable and arguments separately, such as `execFileSync()` or `spawnSync()` with shell processing disabled: ```javascript const { execFileSync } = require("node:child_process"); function sendCommand(cmd) { execFileSync("tmux", [ "send-keys", "-t", "claw", "--", cmd, "C-m" ], { shell: false }); } ``` Apply the same argument-array pattern to all `tmux` operations for defense in depth. Additionally: - Run the Skill under a dedicated, minimally privileged operating-system account. - Restrict filesystem and network access through sandboxing or container isolation. - Validate the input type and enforce reasonable command-length and resource limits. - Add regression tests using inputs containing `$()`, backticks, quotes, semicolons, newlines, and shell redirections. - Verify that test payloads are delivered literally to tmux and never evaluated by the handler's parent shell. ]]>
