From 4881fabb15d7be60e92392ab2cb11cbdaef267a7 Mon Sep 17 00:00:00 2001 From: arabcoders Date: Mon, 8 Jun 2026 09:29:31 +0300 Subject: [PATCH] feat: add YTP_DISABLE_EXEC to strip dangerous yt-dlp options --- FAQ.md | 6 ++++++ app/features/ytdlp/ytdlp_opts.py | 24 ++++++++++++++++++++++++ app/library/config.py | 4 ++++ 3 files changed, 34 insertions(+) diff --git a/FAQ.md b/FAQ.md index 9d836b28..6316ee9e 100644 --- a/FAQ.md +++ b/FAQ.md @@ -60,6 +60,7 @@ or the `environment:` section in `compose.yaml` file. | YTP_THUMB_CONCURRENCY | The number of concurrent ffmpeg thumbnail generations allowed. | `2` | | YTP_THUMB_GENERATE | Enable ffmpeg thumbnail generation when no local thumbnail exists. | `true` | | YTP_THUMB_SIDECAR | Save generated thumbnails next to media instead of temp cache. | `false` | +| YTP_DISABLE_EXEC | Strip some dangerous yt-dlp options. | `false` | > [!NOTE] > To raise the maximum workers for specific extractor, you need to add a ENV variable that follows the pattern `YTP_MAX_WORKERS_FOR_`. @@ -143,6 +144,11 @@ a tool that by design can execute commands. Auth is the mechanism that controls YTPTube already gates other powerful features behind explicit opt-in: the built-in terminal, file browser actions and internal URL requests for example. The `cli` field is no different, its power is by design, and access control is your responsibility. +> [!NOTE] +> If you choose to run without authentication but still want to reduce at least some impact, you can set +> `YTP_DISABLE_EXEC=true`. This strips some dangerous options at run time. However, understand that this is not a +> substitute for auth an unauthenticated API is still fully open for all other operations. + # I cant download anything If you are receiving errors like: diff --git a/app/features/ytdlp/ytdlp_opts.py b/app/features/ytdlp/ytdlp_opts.py index 1d4693c9..80234459 100644 --- a/app/features/ytdlp/ytdlp_opts.py +++ b/app/features/ytdlp/ytdlp_opts.py @@ -397,6 +397,30 @@ class YTDLPOpts: data: dict = merge_dict(user_cli, merge_dict(self._item_opts, merge_dict(self._preset_opts, default_opts))) + if self._config.disable_exec: + stripped: list[str] = [] + if data.pop("netrc_cmd", None): + stripped.append("netrc_cmd") + + if "postprocessors" in data: + exec_pps = [ + pp for pp in data["postprocessors"] if isinstance(pp, dict) and pp.get("key", "").startswith("Exec") + ] + if exec_pps: + stripped.extend(pp.get("key") for pp in exec_pps) + data["postprocessors"] = [ + pp + for pp in data["postprocessors"] + if not (isinstance(pp, dict) and pp.get("key", "").startswith("Exec")) + ] + + if stripped: + LOG.warning( + "Stripped %d dangerous options from yt-dlp options.", + len(stripped), + extra={"stripped": stripped, "reason": "YTP_DISABLE_EXEC is enabled"}, + ) + if not keep: self.reset() diff --git a/app/library/config.py b/app/library/config.py index e1224d39..3baff0b5 100644 --- a/app/library/config.py +++ b/app/library/config.py @@ -110,6 +110,9 @@ class Config(metaclass=Singleton): auth_password: str | None = None """The password to use for basic authentication.""" + disable_exec: bool = False + """Strip some dangerous yt-dlp options.""" + remove_files: bool = False """Remove downloaded files when removing the record.""" @@ -312,6 +315,7 @@ class Config(metaclass=Singleton): "check_for_updates", "thumb_generate", "thumb_sidecar", + "disable_exec", ) "The variables that are booleans."