T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/get_transcript.py:17
- Finding
- Bypassable Hostname Allowlist Permits Requests to Attacker-Controlled Hosts## Vulnerability Details **File Location**: `scripts/get_transcript.py`, lines 17-25; unvalidated URL execution occurs at lines 98-115 **Vulnerability Type**: Improper hostname validation **Risk Level**: Medium ### Vulnerable Code ```python def detect_platform(url: str) -> str: """Detect video platform from URL.""" domain = urlparse(url).netloc.lower() if any(d in domain for d in ['youtube.com', 'youtu.be', 'youtube-nocookie.com']): return 'youtube' elif any(d in domain for d in ['bilibili.com', 'b23.tv']): return 'bilibili' else: return 'unknown' ``` The accepted URL is subsequently passed unchanged to `yt-dlp`: ```python if platform == 'bilibili': cmd.extend([ "--add-header", "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "--add-header", "Referer: https://www.bilibili.com/", ]) cmd.append(url) try: result = subprocess.run(cmd, cwd=temp_dir, check=True, capture_output=True) ``` ### Technical Analysis `detect_platform()` checks whether an allowed domain string occurs anywhere in `urlparse(url).netloc`. This is substring matching rather than validation against an exact hostname or a legitimate subdomain boundary. Consequently, attacker-controlled hostnames such as `youtube.com.attacker.example`, `fakebilibili.com`, or `b23.tv.attacker.example` satisfy the check. The URL is then passed directly to `yt-dlp`, causing the dependency to process and potentially contact a host outside the advertised YouTube and Bilibili trust boundary. Using an argument list with `subprocess.run()` prevents conventional shell metacharacter injection in this code path. The vulnerability is instead an outbound destination-validation weakness. Redirect handling performed by `yt-dlp` may also allow subsequent requests to destinations not ...[truncated 1193 chars]
- Remediation
- ## Remediation Suggestions Validate the parsed hostname using exact equality or a dot-delimited subdomain boundary: ```python from urllib.parse import urlparse ALLOWED_HOSTS = { "youtube": ( "youtube.com", "www.youtube.com", "m.youtube.com", "youtu.be", "youtube-nocookie.com", "www.youtube-nocookie.com", ), "bilibili": ( "bilibili.com", "www.bilibili.com", "b23.tv", ), } def host_matches(host: str, allowed: str) -> bool: return host == allowed or host.endswith("." + allowed) def detect_platform(url: str) -> str: parsed = urlparse(url) host = (parsed.hostname or "").lower().rstrip(".") if parsed.scheme != "https": return "unknown" for platform, allowed_hosts in ALLOWED_HOSTS.items(): if any(host_matches(host, allowed) for allowed in allowed_hosts): return platform return "unknown" ``` Additional hardening should include: 1. Reject URLs containing credentials in the authority component. 2. Permit only required schemes, preferably HTTPS. 3. Define whether arbitrary subdomains are necessary; use exact hostnames where possible. 4. Review and restrict redirect behavior. If redirects must be followed, validate every redirect destination against the same allowlist. 5. Add tests for malicious suffix and prefix cases, including `youtube.com.example.org`, `notyoutube.com`, and `b23.tv.example.org`. 6. Consider applying network-level egress restrictions as defense in depth.
