T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:82
- Finding
- Shell Command Injection Through Unescaped User-Controlled Prompt Content<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:82-83, 145-182` **Vulnerability Type**: Shell command injection **Risk Level**: High ### Vulnerable Code ```text 4. `objective` - use the user request as the execution objective ``` ```text Task ID: <task or N/A> Project Key: <project key or N/A> User Objective: <objective> Execution Requirements: 1) Work only inside <cwd>. 2) Complete the requested work. 3) After completion, return a short completion summary. ``` ```bash bash pty:true workdir:<cwd> command:"claude --dangerously-skip-permissions '<rendered_prompt>'" ``` ```bash bash pty:true workdir:<cwd> command:"codex exec --dangerously-bypass-approvals-and-sandbox '<rendered_prompt>'" ``` ```bash bash pty:true workdir:<cwd> command:"GEMINI_SANDBOX=false gemini -p '<rendered_prompt>'" ``` ### Technical Analysis The skill instructs OpenClaw to use the original user request as the execution objective and interpolate it into `<rendered_prompt>`. That rendered prompt is then placed inside a single-quoted shell argument. No escaping, argument-array construction, or validation is prescribed before the user-controlled objective reaches the shell command. A single quote in the objective can terminate the intended prompt argument. Subsequent shell metacharacters can then introduce an additional command. The prompt template does not mitigate this issue: wrapping untrusted content in a larger template does not make it safe for shell interpolation. ### Attack Path 1. An attacker submits a PREQSTATION request containing a single quote followed by shell syntax. 2. The skill copies the complete request into the `objective` field. 3. The objective is inserted into `<rendered_prompt>`. 4. The rendered prompt is embedded into the documented command as `'<rendered_prompt>'`. 5. The attacker-provided quote terminates the prompt argument. 6. The shell interprets the remaining injected text as syntax or an additional command. 7. The injected command execut ...[truncated 980 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Do not build shell command strings by concatenating prompt content. 2. Invoke each engine through a structured argument array so the prompt is passed as one literal argument without shell parsing. 3. If the execution interface supports only shell command strings, apply a well-tested shell-escaping operation to every dynamic value, such as Bash-compatible `%q` serialization. 4. Prefer passing large prompts through standard input or a securely created prompt file rather than interpolating them into command text. 5. Quote and validate every other dynamic value, including worktree paths, project keys, task identifiers, and engine names. 6. Add regression tests using single quotes, double quotes, command substitutions, semicolons, newlines, backticks, and shell redirection characters. 7. Retain sandbox and approval controls so a quoting failure does not immediately become unrestricted host compromise. ]]>
