Skip to content

Fix: prevent yt-dlp argument injection via unsanitized URL (RCE) - #58

Open
robomello wants to merge 1 commit into
averygan:mainfrom
robomello:fix/ytdlp-arg-injection
Open

Fix: prevent yt-dlp argument injection via unsanitized URL (RCE)#58
robomello wants to merge 1 commit into
averygan:mainfrom
robomello:fix/ytdlp-arg-injection

Conversation

@robomello

Copy link
Copy Markdown

Summary

url from the unauthenticated POST /api/download, /api/info, and /api/playlist endpoints was passed straight into the yt-dlp argv list (app.py). Since it's the last positional argument with nothing separating it from option parsing, a caller can submit something like:

{"url": "--exec=touch /tmp/pwned; true"}

yt-dlp treats any argv item starting with -/-- as a flag rather than a URL, so this reaches --exec (or --exec-before-download, --print, etc.) and results in arbitrary command execution on the host as the process user, with no auth required.

Fix

  • Added is_safe_url() — requires an http/https scheme and a host, rejecting anything that could parse as a CLI flag.
  • Inserted a -- argv separator before the URL in every yt-dlp invocation so option parsing stops at that point regardless of URL content (defense in depth alongside the scheme check).
  • Applied the check to all three endpoints that accept a URL (/api/download, /api/info, /api/playlist).

Testing

  • python3 -m py_compile app.py passes.
  • Manually verified is_safe_url rejects --exec=..., -o=..., empty strings, and non-http(s) schemes, and accepts normal https://... URLs.

Happy to adjust the validation approach (e.g. stricter allow-list of domains) if you'd prefer a different shape for the fix.

The url field from POST /api/download, /api/info, and /api/playlist
was passed straight into the yt-dlp argv list. Since these endpoints
are unauthenticated, a caller could pass a value like
"--exec=<cmd>" instead of a real URL; yt-dlp parses any argv item
starting with "-" as an option rather than a positional URL, so
this allowed arbitrary command execution on the host after a
(fake) download.

Fixes:
- Add is_safe_url() to require an http(s) scheme + host, rejecting
  anything that could be interpreted as a CLI flag.
- Insert a "--" argv separator before the URL in every yt-dlp
  invocation so option parsing stops regardless of URL content
  (defense in depth alongside the scheme check).
- Apply the check on all three endpoints that accept a URL.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant