T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:55
- Finding
- Command Injection Through Untrusted URL, Video Metadata, and Subtitle Content<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:55-64`, `SKILL.md:108-126` **Vulnerability Type**: Command injection through unsafe shell-command construction **Risk Level**: High ### Vulnerable Code ```powershell # SKILL.md:55-64 # Try manual subs first, fall back to auto-generated yt-dlp --skip-download --write-subs --write-auto-subs --sub-langs "en,zh-Hans,zh-Hant,zh" --convert-subs srt -o "$tmp\sub" "<URL>" ``` ```powershell # SKILL.md:108-126 # Original node "~/.agents/skills/video-transcript/scripts/make_docx.js" "$tmp\transcript_original.docx" "<VideoTitle> - Original" "<plain_text>" # Chinese translation node "~/.agents/skills/video-transcript/scripts/make_docx.js" "$tmp\transcript_zh.docx" "<VideoTitle> - 中文译稿" "<chinese_text>" ``` The alternative workflow still interpolates an untrusted title: ```powershell $plain | Out-File -Encoding utf8 "$tmp\content.txt" Get-Content "$tmp\content.txt" -Raw | node "~/.agents/skills/video-transcript/scripts/make_docx.js" "$tmp\transcript_original.docx" "<title>" ``` ### Technical Analysis The documented workflow places user-controlled or remotely controlled values directly into PowerShell command text: - The video URL comes from the user. - The title may come from remote video metadata. - The original transcript can come from remotely hosted subtitles. - The translated transcript is derived from that untrusted subtitle content. Surrounding a substituted value with double quotes is not sufficient when the value itself can contain quotation marks, PowerShell statement separators, subexpressions, or other shell metacharacters. If the agent constructs a textual command by replacing placeholders such as `<URL>`, `<VideoTitle>`, or `<plain_text>`, a malicious value can terminate its quoted argument and introduce additional PowerShell syntax. The stdin-based variant avoids placing the transcript body in an argument, but it continues to place the video title directly into the command. It therefo ...[truncated 1349 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Do not generate shell command strings by interpolating URLs, titles, or transcript content. 2. Invoke child processes through an API that accepts an executable and a structured argument array, with shell processing disabled. For example, use Node.js `spawn` or `execFile` with `shell: false`. 3. Pass transcript content through stdin or a temporary file rather than through a command-line argument. 4. Pass the video title as a discrete process argument through the same structured API. 5. Use the `--` end-of-options separator before the URL where supported, preventing a URL beginning with `-` from being interpreted as an option. 6. If PowerShell must be used, retain values in variables and pass those variables as arguments without constructing and evaluating a new command string. Do not use `Invoke-Expression`. 7. Validate URLs against an explicit set of permitted schemes, such as `https`, and reject control characters, line breaks, and unexpected schemes. 8. Generate output filenames independently from remote metadata. If metadata is used in a filename, normalize it to a conservative allowlist and enforce a known output directory. ]]>
