T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:24
- Finding
- Shell Command Injection Through Unsafe Prompt Interpolation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 24–27; repeated in the editing workflow at lines 468–472 **Vulnerability Type**: Shell command injection **Risk Level**: High ### Vulnerable Code ```bash uv run {nano-banana-pro-dir}/scripts/generate_image.py \ --prompt '<YOUR_JSON_PROMPT>' \ --filename "<descriptive-name>.png" \ --resolution 2K ``` The editing workflow repeats the same unsafe interpolation pattern: ```bash uv run {nano-banana-pro-dir}/scripts/generate_image.py \ --prompt '<JSON_PROMPT>' \ --filename "edited-output.png" \ -i "/path/to/original.png" \ --resolution 2K ``` ### Technical Analysis The Skill instructs the Agent to incorporate content derived from the user's image request into a JSON prompt and then insert that prompt directly into a single-quoted shell argument. Single quotes only protect the argument until another single quote is encountered. If user-controlled content contains an apostrophe followed by shell syntax, it can terminate the quoted argument and introduce an additional command. For example, malicious text conceptually shaped like the following could escape the prompt argument when copied into the generated JSON: ```text '; attacker-controlled-command; # ``` The exact payload depends on how the Agent constructs and submits the command, but the underlying issue is that data and shell syntax are combined in one command string without context-aware escaping. Although `SKILL.md` explicitly requires filename sanitization, it provides no equivalent protection for the more directly user-controlled `--prompt` value. The same concern applies to dynamically substituted generator, input-image, and output paths if they are interpolated into a shell command rather than supplied as separate process arguments. ### Attack Path 1. An attacker submits an image-generation or editing request containing a single quote and shell control operators. 2. The Agent incorporates the attacker-controlled ...[truncated 1558 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Do not construct a shell command by string interpolation.** Invoke the generator with an argument array so the prompt is passed as one literal process argument: ```python subprocess.run( [ "uv", "run", generator_path, "--prompt", json_prompt, "--filename", safe_filename, "--resolution", "2K", ], check=True, shell=False, ) ``` 2. **Prefer a prompt file or standard input for large JSON values.** Write the JSON to a securely created file with restrictive permissions and pass a file path to the generator, or update the generator to accept the prompt through standard input. Avoid predictable temporary filenames. 3. **If a shell is unavoidable, use a proven quoting mechanism.** Apply shell escaping to every dynamic argument rather than adding quotes manually. The preferred remediation remains avoiding the shell entirely. 4. **Validate all dynamic paths.** - Resolve the generator path from a trusted Skill installation directory. - Generate output filenames from a strict allowlist such as letters, digits, hyphens, and a fixed image extension. - Treat reference-image and user-selected output paths as data, not shell syntax. - Use path normalization and enforce intended directory boundaries where applicable. 5. **Update both documented workflows.** Correct the generation example at lines 24–27 and the editing example at lines 468–472 so Agents are not instructed to execute unsafe command templates. 6. **Add adversarial tests.** Verify safe handling of prompts containing apostrophes, quotes, semicolons, command substitutions, newlines, backticks, and shell redirection characters. ]]>
