T09 · Insecure Skill Coding Practices
- Location
SKILL.md:50- Finding
Shell Command Injection Through Unvalidated User-Controlled Parameters
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md:50-55, 74-75;SKILL-CN.md:51-56, 75-76
Vulnerability Type: OS command injection
Risk Level: HighThe English and Chinese Skill documents instruct the agent to interpolate user-controlled video paths, output paths, frame rates, and scale values directly into shell commands.
Vulnerable code in
SKILL.md:bash ffmpeg -hide_banner -loglevel error -i "{video_path}" -vf "fps={frame_rate}" -fps_mode vfr -q:v 2 -f image2 "{output_path}/%06d.jpg"bash ffmpeg -hide_banner -loglevel error -thread_queue_size 512 -i "{video_path}" -vf "fps={frame_rate},scale='if(gt(iw,ih),-2,{scale}):if(gt(iw,ih),{scale},-2)':flags=lanczos" -fps_mode vfr -q:v 2 -f image2 -atomic_writing 1 "{output_path}/%06d.jpg"bash ls {output_path}/*.jpg | wc -l ls -lh {output_path}/*.jpg | head -5The equivalent commands appear in
SKILL-CN.mdat lines 51-56 and 75-76.Technical Analysis
The placeholders
{video_path},{output_path},{frame_rate}, and{scale}originate from values supplied or confirmed by the user. The Skill does not require syntactic validation, canonicalization, shell-safe escaping, or execution through a structured argument array.Quoting paths with double quotes is not a complete defense. POSIX-compatible shells still process command substitutions such as
$(...)inside double-quoted strings. An embedded double quote can also terminate the intended quoted argument and expose subsequent shell metacharacters. The output verification commands are more directly exposed because{output_path}is entirely unquoted.Numeric parameters are also inserted into the
-vfargument without validation. Although FFmpeg filter syntax limits some payload forms, shell substitutions are processed by the shell before FFmpeg receives the argument. Consequently, a malicious parameter may execute a command even if it is not a valid FFmpeg value.The ...[truncated 1851 chars]
- Remediation
View remediation
Remediation Suggestions
-
Do not execute generated command strings through a shell. Invoke FFmpeg with a process API that accepts an argument array, keeping each path and option as a separate argument.
python subprocess.run( [ "ffmpeg", "-hide_banner", "-loglevel", "error", "-i", video_path, "-vf", f"fps={frame_rate}", "-fps_mode", "vfr", "-q:v", "2", "-f", "image2", str(output_path / "%06d.jpg"), ], shell=False, check=True, ) -
Validate numeric parameters before command construction.
- Parse
frame_rateas a finite positive decimal and enforce an appropriate upper bound. - Parse
scaleas an integer within a documented range. - Construct the filter expression only from parsed numeric values, not raw user input.
- Parse
-
Validate and canonicalize paths.
- Reject NUL bytes and control characters.
- Resolve paths against an explicitly permitted workspace.
- Prevent output-directory traversal where extraction must remain sandboxed.
- Confirm that the input is a permitted regular file and that the destination is a permitted directory.
-
Replace shell verification pipelines with filesystem APIs. Enumerate JPEG files, count them, and inspect their sizes through the implementation language rather than interpolating paths into
ls,wc, orhead. -
If shell execution is unavoidable, apply platform-specific escaping to every dynamic value. This is a secondary defense and should not replace shell-free execution. Use
--before path operands where supported to prevent paths beginning with a hyphen from being interpreted as options. -
Update both localized Skill documents consistently. Explicitly require shell-free execution and include the same validation rules in
SKILL.mdandSKILL-CN.md. -
**Run extraction ...[truncated 208 chars]
-
