T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/download.sh:15
- Finding
- Weak YouTube URL Validation Permits Requests to Arbitrary Hosts<![CDATA[ ## Vulnerability Details **File Location**: `scripts/download.sh`, lines 15–25 and 44–51 **Vulnerability Type**: Insufficient URL validation **Risk Level**: Medium ### Vulnerable Code ```bash # Extract video ID if [[ "$URL" == *"youtu.be/"* ]]; then VIDEO_ID=$(echo "$URL" | sed 's/.*youtu\.be\///' | sed 's/\?.*//') elif [[ "$URL" == *"youtube.com/watch"* ]]; then VIDEO_ID=$(echo "$URL" | sed 's/.*v=//' | sed 's/&.*//') elif [[ "$URL" == *"youtube.com/shorts/"* ]]; then VIDEO_ID=$(echo "$URL" | sed 's/.*shorts\///' | sed 's/\?.*//') else echo "ERROR: Invalid YouTube URL" exit 1 fi # Download with yt-dlp at best quality yt-dlp \ -f "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best" \ --merge-output-format mp4 \ -o "$OUTPUT_PATH" \ --no-playlist \ --no-warnings \ "$URL" ``` ### Technical Analysis The script determines whether a URL is a YouTube URL using shell substring comparisons. It does not parse the URL or verify that its hostname is an authorized YouTube domain. For example, the following attacker-controlled URL contains the accepted string but does not belong to YouTube: ```text https://attacker.example/youtube.com/watch?v=test ``` Because the string contains `youtube.com/watch`, it passes validation and is supplied directly to `yt-dlp`. Depending on the protocols and extractors supported by the installed `yt-dlp` version, this can cause the process to connect to and retrieve content from an attacker-selected host. This is not shell command injection because `"$URL"` is quoted. The security problem is that the semantic destination of the network request is not restricted to the declared YouTube service. ### Attack Path 1. An attacker or untrusted user submits a URL whose path or query contains an accepted YouTube substring. 2. The substring comparison treats the URL as an authorized YouTube URL without validating its hostname. 3. The complete attacker-controlled URL is passed to `yt-dlp ...[truncated 901 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Parse and validate the URL before invoking `yt-dlp`: 1. Require the `https` scheme. 2. Compare the parsed hostname against an explicit allowlist such as: - `youtube.com` - `www.youtube.com` - `m.youtube.com` - `youtu.be` 3. Reject hostnames that merely end with or contain an allowed name, such as `youtube.com.attacker.example`. 4. Reject URLs containing user-information components that may obscure the actual host. 5. Restrict accepted paths to the documented watch, short-link, and shorts formats. 6. Validate the port or reject non-default ports. 7. Consider resolving the hostname and applying network egress controls if requests to private or loopback address ranges are not required. A structured URL parser should be used instead of substring matching. After validation, pass a canonicalized URL to `yt-dlp`. ]]>
