T09 · Insecure Skill Coding Practices
- Location
scripts/analyze_video.py:51- Finding
Unrestricted Video URL Fetching Enables Server-Side Request Forgery
- Content
View full analysis
Vulnerability Details
File Location:
scripts/analyze_video.py:51-58,scripts/analyze_video.py:258-270, andscripts/analyze_video.py:762-776
Vulnerability Type: Server-Side Request Forgery and insecure HTTP transport
Risk Level: MediumVulnerable Code
python def validate_source(source: str) -> None: if local_video_path(source): return parsed = urlsplit(source) if parsed.scheme not in ("https", "http") or not parsed.hostname or parsed.username or parsed.password: raise ValueError("Use an existing local video or a credential-free HTTP(S) URL") sensitive = {"token", "access_token", "api_key", "apikey", "password", "signature", "sig", "authorization", "key"} query_keys = {key.lower() for key in parse_qs(parsed.query, keep_blank_values=True)} if query_keys & sensitive or any(key.startswith(("x-amz-", "x-goog-")) for key in query_keys): raise ValueError("Do not place credentials in command arguments; use an authorized local download")python def download_video(url: str, output_path: str, max_size_mb: int = 500) -> str: """Download video using yt-dlp. Returns the actual output file path.""" cmd = [ "yt-dlp", "--ignore-config", "-f", "bestvideo+bestaudio/best", "--merge-output-format", "mp4", "--remux-video", "mp4", "--no-playlist", "--max-filesize", f"{max_size_mb}M", "-o", output_path, "--", url, ] print("Downloading video source...", file=sys.stderr) result = subprocess.run(cmd, capture_output=True, text=True)python # Download for non-YouTube tmp_dir = None if args.download_only and args.output: video_path = args.output else: tmp_dir = tempfile.mkdtemp() video_path = os.path.join(tmp_dir, "video.%(ext)s") try: video_path = download_video(args.url, video_path, args.max_size) if args.download_only: print("Saved requested output", file=sys.stderr) return ...[truncated 2866 chars]- Remediation
View remediation
Remediation Suggestions
- Require HTTPS for remote sources by default. If HTTP support is operationally necessary, make it an explicit privileged option and warn that transport integrity is unavailable.
- Resolve destination hostnames and reject all loopback, private, link-local, multicast, unspecified, reserved, and cloud metadata addresses for both IPv4 and IPv6.
- Apply the same checks after every redirect and to all extractor, manifest, segment, and CDN requests. Initial URL validation alone is insufficient.
- Protect against DNS rebinding by binding validated resolutions to actual outbound connections where possible.
- Prefer a configurable allowlist of trusted video providers when processing requests from untrusted users.
- Run
yt-dlp,ffmpeg, and related child processes in an isolated sandbox with no access to internal networks, metadata services, or unnecessary filesystem resources. - Enforce network egress controls outside the process, such as a restricted proxy, firewall rules, or an isolated network namespace. This should be the primary SSRF boundary.
- Prevent content obtained from private or unapproved destinations from being uploaded to Gemini.
- Add tests covering direct and redirected requests to loopback, RFC1918, link-local, IPv6 local, reserved, and cloud metadata addresses.
- Retain the existing privacy documentation, but do not treat documentation or user authorization as a substitute for destination-level network controls.
