mirror of
https://github.com/alexta69/metube.git
synced 2026-09-21 13:35:01 +00:00
fix: enforce download-dir containment at the resolved-path chokepoint
The per-download chapter_template was validated only against literal ".." in the template string, but yt-dlp expands %(section_title)s (and every other field) from attacker-controlled metadata at download time. On POSIX hosts yt-dlp does not neutralise a ".." path component, so a chapter titled ".." turns a guard-passing template like "%(section_title)s/%(section_title)s/x.%(ext)s" into "../../x.mp4" and writes outside DOWNLOAD_DIR. The same class of escape applies to any multi-segment output template (default/playlist/channel) whose fields resolve to "..". The template string can never see the "..": it only exists after expansion. So move the check to the one point every output path flows through — YoutubeDL.prepare_filename — via a _ConfinedYoutubeDL subclass that refuses any resolved path outside the download/temp roots (fail closed). This covers the main file, split-chapter files, thumbnails and subtitles in one place. With the chokepoint authoritative, the scattered ingress string checks (chapter_template, custom_name_prefix) and the weaker _output_dir_escapes literal-prefix check are removed. Tests move from the ingress layer to the chokepoint, exercising the real metadata-resolution vector. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -717,8 +717,6 @@ def parse_download_options(post: dict) -> dict:
|
||||
|
||||
if custom_name_prefix is None:
|
||||
custom_name_prefix = ''
|
||||
if custom_name_prefix and ('..' in custom_name_prefix or custom_name_prefix.startswith('/') or custom_name_prefix.startswith('\\')):
|
||||
raise web.HTTPBadRequest(reason='custom_name_prefix must not contain ".." or start with a path separator')
|
||||
if auto_start is None:
|
||||
auto_start = True
|
||||
if playlist_item_limit is None:
|
||||
@@ -743,8 +741,6 @@ def parse_download_options(post: dict) -> dict:
|
||||
enabled=config.ALLOW_YTDL_OPTIONS_OVERRIDES,
|
||||
)
|
||||
|
||||
if chapter_template and ('..' in chapter_template or chapter_template.startswith('/') or chapter_template.startswith('\\')):
|
||||
raise web.HTTPBadRequest(reason='chapter_template must not contain ".." or start with a path separator')
|
||||
if not SUBTITLE_LANGUAGE_RE.fullmatch(subtitle_language):
|
||||
raise web.HTTPBadRequest(reason='subtitle_language must match pattern [A-Za-z0-9-] and be at most 35 characters')
|
||||
if subtitle_mode not in VALID_SUBTITLE_MODES:
|
||||
|
||||
Reference in New Issue
Block a user