T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:26
- Finding
- Shell Command Injection Through Image-Generation Prompt Interpolation## Vulnerability Details **File Location**: `SKILL.md`, lines 26-46 **Vulnerability Type**: Shell command injection through unsafe interpolation **Risk Level**: High ### Vulnerable Code ```bash curl -s https://api.x.ai/v1/images/generations \ -H "Authorization: Bearer $XAI_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "model": "grok-imagine-image-pro", "prompt": "<PROMPT>", "n": 1, "response_format": "b64_json" }' | python3 -c " import json, sys, base64, os, time os.makedirs(os.path.expanduser('~/.openclaw/media'), exist_ok=True) r = json.load(sys.stdin) ts = int(time.time()) for i, img in enumerate(r['data']): img_data = base64.b64decode(img['b64_json']) fpath = os.path.expanduser(f'~/.openclaw/media/generated_{ts}_{i}.png') with open(fpath, 'wb') as f: f.write(img_data) print(fpath) " ``` ### Technical Analysis The documentation instructs the Agent to substitute a user-supplied image prompt directly into a single-quoted shell argument. No JSON serialization or shell-safe argument handling is applied. If the prompt contains a single quote followed by shell syntax, it can terminate the `--data` argument and introduce additional shell commands. JSON double quotes do not protect the value from shell parsing because the entire JSON document is enclosed in shell single quotes. This is especially dangerous in an Agent Skill because image prompts are expected to originate from users and may therefore be attacker-controlled. ### Attack Path 1. An attacker submits an image-generation request containing a prompt with a single quote, shell separators, and an injected command. 2. The Agent replaces `<PROMPT>` with that content as instructed by the Skill. 3. The injected quote terminates the shell's single-quoted JSON argument. 4. The shell interprets the remaining attacker-controlled content as commands. 5. Those commands ...[truncated 592 chars]
- Remediation
- ## Remediation Suggestions - Do not construct executable shell text by substituting the prompt into a quoted command. - Build the complete request body using a Python script and `json.dump` or `json.dumps`. - Supply the prompt through a non-executable channel, such as a Python argument, standard input, or a narrowly scoped environment variable. - Invoke the HTTP client through `subprocess.run` with an argument array and `shell=False`, or perform the request directly with a vetted HTTP library. - Validate maximum prompt length and reject unexpected control characters. - Run the image-generation process in a restricted environment with minimal filesystem and network access.
