Skip to content

Security: yt-dlp SSRF bypass in transcribe.download_audio #592

Description

@Theprofitplatform

Summary

transcribe.download_audio shells out to yt-dlp directly on the user-supplied URL without going through security.validate_url. The SSRF guards in security.py (private-IP block, link-local block, scheme allowlist) are bypassed for the YouTube/audio ingest path.

Where

  • graphify/transcribe.py:48-88download_audio builds a yt-dlp argv from the URL and runs it; no validate_url call on the path.

Impact

SECURITY.md documents the SSRF guards in validate_url / safe_fetch but does not disclose this exemption. If a caller passes an attacker-controlled URL through this path:

  • yt-dlp will attempt many extractors against the host, including ones that fall back to direct HTTP fetches.
  • yt-dlp does not honor your _NoFileRedirectHandler and has its own redirect-following logic.
  • A URL pointed at internal infrastructure (e.g. metadata endpoints, internal APIs) bypasses every check validate_url performs.

This is the same class of issue as the DNS rebinding one I just filed (#591) — same underlying assumption ("our SSRF guard runs on every URL") doesn't actually hold.

Suggested fix shape

Two reasonable options, depending on how strict you want to be:

  1. Allowlist hosts. yt-dlp is realistically used against ~10 video platforms in this codebase. Validate the URL host against a small allowlist (youtube.com, youtu.be, vimeo.com, …) before calling yt-dlp. Cheapest defence.
  2. Run validate_url first, then pass to yt-dlp. Catches the link-local / private-IP cases. Doesn't help if yt-dlp itself follows a redirect to a private IP — so combine with --no-redirect if yt-dlp supports it for your use case.

Happy to PR #1 if you'd like.

Related

This was found alongside the issues fixed in #589 (cache race + clone arg injection) and #591 (DNS rebinding TOCTOU), but it's a distinct exposure so I'm filing separately.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions