[pp/exec] Restrict --exec template usage to safe conversions (#16883)

Authored by: bashonly
This commit is contained in:
bashonly
2026-06-06 21:24:53 +00:00
committed by GitHub
parent 7aac95eae6
commit 5faffa999f
7 changed files with 103 additions and 15 deletions
+22 -4
View File
@@ -112,6 +112,7 @@ from .utils import (
RejectedVideoReached,
SameFileError,
UnavailableVideoError,
UnsafeExecExpansionError,
UserNotLive,
YoutubeDLError,
age_restricted,
@@ -826,9 +827,14 @@ class YoutubeDL:
for pp_def_raw in self.params.get('postprocessors', []):
pp_def = dict(pp_def_raw)
when = pp_def.pop('when', 'post_process')
self.add_post_processor(
get_postprocessor(pp_def.pop('key'))(self, **pp_def),
when=when)
# Handle errors for ExecPP command validation
try:
self.add_post_processor(
get_postprocessor(pp_def.pop('key'))(self, **pp_def),
when=when)
except UnsafeExecExpansionError as e:
self.report_error(e)
raise
def preload_download_archive(fn):
"""Preload the archive, if any is specified"""
@@ -1254,7 +1260,7 @@ class YoutubeDL:
info_dict.pop('__pending_error', None)
return info_dict
def prepare_outtmpl(self, outtmpl, info_dict, sanitize=False):
def prepare_outtmpl(self, outtmpl, info_dict, sanitize=False, *, _exec=False):
""" Make the outtmpl and info_dict suitable for substitution: ydl.escape_outtmpl(outtmpl) % info_dict
@param sanitize Whether to sanitize the output as a filename
"""
@@ -1305,6 +1311,8 @@ class YoutubeDL:
(?:&(?P<replacement>.*?))?
(?:\|(?P<default>.*?))?
)$''')
SAFE_EXEC_CONVERSIONS = 'difq'
UNSAFE_DEFAULT_CHARS = '"\' \n\t;&|^$%*<>{}()[]`#\\'
def _from_user_input(field):
if field == ':':
@@ -1429,6 +1437,16 @@ class YoutubeDL:
if fmt == 's' and last_field in field_size_compat_map and isinstance(value, int):
fmt = f'0{field_size_compat_map[last_field]:d}d'
# Validate safety of exec commands
if _exec:
if fmt[-1] not in SAFE_EXEC_CONVERSIONS:
raise UnsafeExecExpansionError(f'Unsafe conversion(s) in exec command: {outtmpl!r}')
elif any(unsafe_char in default for unsafe_char in UNSAFE_DEFAULT_CHARS):
if default == na:
raise UnsafeExecExpansionError(f'Unsafe placeholder for exec command: {na!r}')
else:
raise UnsafeExecExpansionError(f'Unsafe default(s) in exec command: {outtmpl!r}')
flags = outer_mobj.group('conversion') or ''
str_fmt = f'{fmt[:-1]}s'
if value is None: