T09 · Insecure Skill Coding Practices
- Location
plugin/index.ts:32- Finding
Arbitrary Command Execution Through Shell-Interpolated User Queries
- Content
View full analysis
{ try { const effective = resolveSearchProfile(query, config); const escapedQuery = query.replace(/"/g, '\\"'); const { stdout } = await execAsync( `python3 /root/.openclaw/workspace/soul-memory/cli.py search "${escapedQuery}" --top_k ${effective.topK} --min_score ${effective.minScore}`, { timeout: 5000, cwd: '/root/.openclaw/workspace/soul-memory' } ); ``` ### Technical Analysis The plugin obtains a query from a user message and interpolates it into a command passed to Node.js `child_process.exec`. The `exec` API launches a shell, so shell syntax embedded in the query is evaluated before Python receives the argument. The implementation only escapes double quotes. This does not neutralize command substitution expressions such as `$(command)` or backtick substitution, both of which remain active inside a double-quoted shell argument. Shell metacharacters can therefore be used to execute commands under the OpenClaw process account. The 200-character query limit and command timeout do not prevent exploitation. A short command can launch a detached process, modify local files, access credentials, or establish persistence before the timeout expires. ### Attack Path 1. An attacker submits a user message containing a command-substitution expression. 2. The `before_prompt_build` hook treats the message as a memory-search query. 3. `extractQuery()` passes the attacker-controlled text to `searchMemories()`. 4. `searchMemories()` embeds the text in a command string. 5. `execAsync()` invokes a shell. 6. The shell evaluates the embedded expression before invoking `cli.py`. 7. The attacker’s command executes with the permissions of the OpenCl ...[truncated 640 chars]- Remediation
View remediation
