T09 · Insecure Skill Coding Practices
- Location
SKILL.md:78- Finding
Command Injection Through Shell-Based Image Path Handling
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md:78-93
Vulnerability Type: Command injection caused by interpolating a user-controlled file path intosh -c
Risk Level: HighVulnerable Code
python subprocess.run([ "sh", "-c", "cat 'IMAGE_FILE_PATH' | python3 scripts/scan_filter.py --method METHOD_VALUE" ])The alternative Base64 workflow also unnecessarily invokes a shell:
python img_bytes = base64.b64decode("IMAGE_BASE64_DATA") with tempfile.NamedTemporaryFile(delete=False, suffix=".bin") as f: f.write(img_bytes) tmp_path = f.name subprocess.run([ "sh", "-c", f"cat '{tmp_path}' | python3 scripts/scan_filter.py --method METHOD_VALUE" ]) os.unlink(tmp_path)Technical Analysis
The Skill instructs the Agent to replace
IMAGE_FILE_PATHwith the user-supplied local image path and execute the resulting text throughsh -c. Althoughsubprocess.runreceives a list, this does not prevent command injection because the list explicitly launches a command interpreter. The shell parses the entire third argument as shell syntax.Wrapping the path in single quotes is insufficient. A file path containing a single quote can terminate the quoted string and introduce shell operators or additional commands. Consequently, the documentation's claim that list-style subprocess invocation avoids shell injection is incorrect for this execution pattern.
The Base64 workflow uses a Python-generated temporary path and therefore has a substantially lower direct injection risk, but the shell and
catprocess remain unnecessary. The local-file workflow is directly exploitable when an attacker can influence the image path supplied to the Agent.Attack Path
- An attacker submits a request that identifies an image through a crafted local path containing a single quote and shell syntax.
- The Agent follows the mandatory instructions in
SKILL.mdand substitutes that value forIMAGE_FILE_PATH. - The Agen ...[truncated 1183 chars]
- Remediation
View remediation
Remediation Suggestions
Remove
sh -candcatentirely. Open the selected image directly and connect it to the child process through standard input:python from pathlib import Path import subprocess script_path = Path(__file__).resolve().parent / "scripts" / "scan_filter.py" with open(image_path, "rb") as image: subprocess.run( [ "python3", str(script_path), "--method", str(method), ], stdin=image, check=False, )Additional hardening should include:
- Treat the path exclusively as data and never interpolate it into shell command text.
- Resolve the script using a trusted absolute path rather than relying on the current working directory.
- Continue restricting
methodto the documented integer allowlist. - If path access should be constrained, resolve the requested path and enforce an allowlisted input directory.
- For Base64 input, pass decoded bytes directly through the
inputargument or a temporary file object without invoking a shell. - Update the security documentation to avoid claiming that list arguments are safe when the invoked executable is a command interpreter.
