T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:10
- Finding
- Shell Command Injection Through User-Controlled Expense Arguments<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 10-12 **Vulnerability Type**: Shell command injection caused by unsafe interpolation of user-controlled values **Risk Level**: High ### Vulnerable Code Snippet ```text - Extract the amount (`amount`), category (`category`), and description (`desc`). - Call: python3 /home/hoang/.openclaw/workspace/expense-tracker/scripts/finance_manager.py log --amount <amount> --category <category> --desc "<description>" ``` ### Technical Analysis The skill instructs the agent to construct an `exec` command by directly interpolating expense data extracted from the user's message. The dynamic `amount` and `category` arguments are unquoted, while `desc` is only enclosed in double quotes. Double quotes do not prevent shell evaluation of command substitutions such as `$(command)` or backticks. A description containing an embedded quote may also terminate the intended argument and introduce additional shell syntax. Unquoted category or amount values provide further injection opportunities if the agent does not strictly validate them before constructing the command. The Python script's use of `argparse` does not mitigate this vulnerability because shell parsing and command substitution occur before Python receives the argument list. ### Attack Path 1. An attacker submits an expense-recording request containing a crafted field, for example a description equivalent to `$(touch /tmp/expense-skill-pwned)`. 2. The agent extracts the crafted text as the expense description. 3. Following `SKILL.md`, the agent interpolates it into the documented shell command: ```sh python3 /home/hoang/.openclaw/workspace/expense-tracker/scripts/finance_manager.py log --amount 50000 --category Food --desc "$(touch /tmp/expense-skill-pwned)" ``` 4. If `exec` invokes a shell, the shell evaluates the command substitution before launching `finance_manager.py`. 5. The injected command executes with the operating-system pri ...[truncated 1009 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Do not construct a shell command by concatenating or interpolating user-controlled text. 2. Invoke the script through an API that accepts an argument array and disables shell processing: ```python subprocess.run( [ "python3", "/home/hoang/.openclaw/workspace/expense-tracker/scripts/finance_manager.py", "log", "--amount", validated_amount, "--category", validated_category, "--desc", description, ], shell=False, check=True, ) ``` 3. Update `SKILL.md` to explicitly require structured argument passing with no shell and prohibit interpolation into command strings. 4. Validate `amount` using a strict numeric parser and enforce an appropriate nonnegative range. 5. Restrict `category` to the documented allowlist: `Food`, `Drink`, `Transport`, `Shopping`, or `Other`. 6. Treat `desc` as opaque data. Do not attempt to make unsafe shell interpolation acceptable through ad hoc filtering. 7. If the execution interface can accept only shell text, apply a proven platform-specific shell-quoting routine independently to every dynamic argument. This is a fallback rather than the preferred design. 8. Add regression tests covering command substitutions, embedded quotes, semicolons, redirection operators, newlines, backticks, and option-like values. ]]>
