From 13cb65d931c915ffaa63cd6c836a764c4a3f91b1 Mon Sep 17 00:00:00 2001 From: Alex Shnitman Date: Tue, 21 Jul 2026 07:41:01 +0300 Subject: [PATCH] docs: document the SSRF guard's connect-time coverage limitations The connect-time getaddrinfo guard added for redirect/rebinding SSRF covers only the download subprocess: metadata extraction runs in the main process (where a process-wide guard would reject the server's own HOST=0.0.0.0 bind), and native curl_cffi/libcurl resolution used by --impersonate bypasses Python's socket module. Record both in url_guard's docstring and at the extraction site so the boundary is explicit; network isolation remains the backstop. Co-Authored-By: Claude Fable 5 --- app/url_guard.py | 14 ++++++++++++-- app/ytdl.py | 5 +++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/app/url_guard.py b/app/url_guard.py index d4b91ee..8d59f86 100644 --- a/app/url_guard.py +++ b/app/url_guard.py @@ -13,8 +13,18 @@ This module provides two layers: covers redirects, DNS rebinding, and media URLs yt-dlp derives from remote metadata — for any backend that resolves through Python's socket module. -Native resolvers (curl_cffi/libcurl via ``--impersonate``) bypass the socket -guard; network isolation (e.g. Docker) remains the backstop for those. +Known limitations — network isolation (e.g. Docker) remains the backstop for +all of these: + +* The socket guard is installed only in the download subprocess. Metadata + extraction (``ytdl.DownloadQueue.__extract_info``) runs in the main process, + where installing a process-wide guard would reject the server's own bind on + ``HOST=0.0.0.0``. So extraction — which also follows redirects — is covered + only by ``validate_url`` at ingress, not at connect time; a redirect from an + allowed host to an internal one during extraction is not blocked (a lower- + impact, blind SSRF, since the extraction response is not written to disk). +* Native resolvers (curl_cffi/libcurl via ``--impersonate``) resolve outside + Python's socket module and bypass the connect-time guard entirely. """ import ipaddress diff --git a/app/ytdl.py b/app/ytdl.py index dc485fc..20cf2da 100644 --- a/app/ytdl.py +++ b/app/ytdl.py @@ -1269,6 +1269,11 @@ class DownloadQueue: return opts def __extract_info(self, url, ytdl_options_presets=None, ytdl_options_overrides=None): + # NOTE: extraction runs in the main process, so the connect-time socket + # guard (installed only in the download subprocess) does not apply here. + # The ingress validate_url check guards the submitted URL, but redirects + # followed during extraction are not re-validated. See url_guard's module + # docstring for why the guard can't be installed process-wide. debug_logging = logging.getLogger().isEnabledFor(logging.DEBUG) user_opts = self._build_ytdl_options(ytdl_options_presets, ytdl_options_overrides) params = {