T09 · Insecure Skill Coding Practices
Error
- Location
- references/config-schema.md:109
- Finding
- Arbitrary Command Execution Through Shell Substitution in Cron Prompts<![CDATA[ ## Vulnerability Details **File Location**: `references/config-schema.md:109`, `references/prompt-patterns.md:98-105`, and `SKILL.md:115-124` **Vulnerability Type**: Command injection through shell-evaluated prompt content **Risk Level**: High ### Vulnerable Code `references/config-schema.md:109`: ```markdown | `payload.message` | Prompt sent to agent. `$(...)` shell substitution works. | ``` `references/prompt-patterns.md:98-105`: ```markdown `$(...)` is evaluated before reaching the LLM: | Expression | Output | |------------|--------| | `$(date '+%A, %B %d, %Y')` | `Wednesday, February 11, 2026` | | `$(date '+%b %d, %Y')` | `Feb 11, 2026` | | `$(date '+%I:%M %p %Z')` | `09:00 AM MST` | | `$(date +%Y-%m-%d)` | `2026-02-11` | ``` `SKILL.md:115-124`: ```markdown Edit `cron/jobs.json`. Every cron job prompt MUST include: - **Dynamic group ID resolution preamble** (NEVER hardcode Telegram group IDs): ``` FIRST: Resolve your Telegram group ID by running: jq -r '.bindings[] | select(.agentId == "<agent_id>") | .match.peer.id' ~/.openclaw/openclaw.json Use the output as the target for all Telegram messages in this task. ``` - **Date injection**: `$(date '+%A, %B %d, %Y')` after the preamble - **Explicit constraints**: source allowlists, recency rules, format templates - **Delivery instructions**: use `target='<AGENT_GROUP_ID>'` placeholder (resolved by the preamble) ``` ### Technical Analysis The documented cron configuration permits `$(...)` expressions in `payload.message` and states that they are evaluated before the prompt reaches the LLM. This crosses a trust boundary: text intended to serve as an LLM prompt is also interpreted as shell syntax. The Skill creates cron prompts from user-supplied task requirements but does not require validation or escaping of prompt content. It also does not restrict shell substitutions to the documented `date` expressions. Consequently, a malicious requirement containing a substitution such as `$(a ...[truncated 1633 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Disable shell evaluation for `payload.message`; treat the entire prompt as inert data. 2. Generate dates in trusted application code and insert the resulting value without invoking a shell. 3. If backward compatibility requires substitution, enforce an exact allowlist of supported expressions rather than accepting arbitrary `$(...)`. 4. Reject externally influenced prompt text containing `$(`, backticks, command separators, redirects, pipes, control characters, or other shell syntax. 5. Keep user-controlled task content separate from scheduler metadata and pass it through a non-shell serialization interface. 6. Validate the final `cron/jobs.json` payload before writing it and refuse unsafe expressions. 7. Run scheduled jobs under a dedicated, least-privileged account with restricted filesystem and network access. 8. Add tests proving that strings such as `$(id)`, backtick substitutions, multiline shell syntax, and nested substitutions remain literal and are never executed. ]]>
