T09 · Insecure Skill Coding Practices
- Location
SKILL.md:41- Finding
Shell Command Injection Through Unescaped User Prompt
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 41-54
Vulnerability Type: Shell command injection caused by direct interpolation of untrusted input
Risk Level: HighVulnerable Code
bash # Same prompt, 3 times uv run ~/.npm-global/lib/node_modules/clawdbot/skills/nano-banana-pro/scripts/generate_image.py \ --prompt "[USER'S EXACT PROMPT]" \ --filename "option-1.png" --resolution 1K uv run ~/.npm-global/lib/node_modules/clawdbot/skills/nano-banana-pro/scripts/generate_image.py \ --prompt "[USER'S EXACT PROMPT]" \ --filename "option-2.png" --resolution 1K uv run ~/.npm-global/lib/node_modules/clawdbot/skills/nano-banana-pro/scripts/generate_image.py \ --prompt "[USER'S EXACT PROMPT]" \ --filename "option-3.png" --resolution 1KTechnical Analysis
The skill instructs the agent to insert the user's exact prompt into a Bash command. The prompt is untrusted input, but the documented invocation does not require an argument-array execution API, shell escaping, or disabling shell interpretation.
Double quotes do not prevent every form of shell evaluation. In particular, command substitution expressions such as
$(command)and backtick substitutions are evaluated inside double-quoted strings. A prompt containing an embedded quotation mark may also terminate the intended argument and append shell operators or additional commands.The requirement to preserve the user's “EXACT prompt” increases the likelihood that metacharacters will be copied without validation. Because the same prompt is used in all three commands, injected behavior may execute three times if all invocations are performed independently.
This finding applies when the displayed commands are assembled as command strings and executed through a shell. An implementation that passes the prompt as a distinct argument through a shell-free process API would not be vulnerable to shell expansion.
Attack Path
- An attacker submits an image request whose p ...[truncated 1361 chars]
- Remediation
View remediation
Remediation Suggestions
- Do not construct a shell command by interpolating the prompt into a command string.
- Invoke the Python script through a process API that accepts an argument array and disables shell processing. Pass the prompt as one distinct argument, for example conceptually:
python subprocess.run( [ "uv", "run", script_path, "--prompt", user_prompt, "--filename", output_filename, "--resolution", "1K", ], shell=False, check=True, )- Update
SKILL.mdto explicitly require shell-free execution and warn that the prompt must never be evaluated as shell syntax. - If Bash cannot be avoided, pass the prompt through a positional parameter or another mechanism that keeps data separate from shell code. Apply robust shell escaping rather than placing raw input between quotation marks.
- Validate output filenames separately and constrain them to an approved output directory.
- Run image generation with least privilege, a restricted environment, and only the filesystem and network access needed for the task.
- Add tests using prompts containing quotation marks, semicolons, newlines,
$(), backticks, redirection operators, and shell control operators. Verify that every prompt reaches the image-generation script as one literal argument and that no additional command executes.
