From 456a513034e9e424ab6bec7b5b3542fe6b85078a Mon Sep 17 00:00:00 2001 From: Tomas Dvorak Date: Sat, 19 Sep 2026 10:04:15 +0200 Subject: [PATCH] fix(downloader): sanitize yt-dlp output template filename The user-chosen remote-download filename becomes a yt-dlp -o template verbatim - "../" could escape the task temp dir and "%(field)s" could expand yt-dlp metadata. Names with path separators, template fields, or ".." now fall back to the default %(title)s.%(ext)s template. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- pkg/filemanager/workflows/remote_download.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/filemanager/workflows/remote_download.go b/pkg/filemanager/workflows/remote_download.go index facc75b4..edcf2490 100644 --- a/pkg/filemanager/workflows/remote_download.go +++ b/pkg/filemanager/workflows/remote_download.go @@ -301,7 +301,11 @@ func (m *RemoteDownloadTask) buildDownloadOptions(ctx context.Context, base map[ } case types.DownloaderProviderYtDlp: if isHttpSrc { - if m.state.FileName != "" { + // "output" becomes a yt-dlp -o template: reject path separators + // and "%(" template fields so a user-chosen name cannot escape + // the task temp dir or expand yt-dlp metadata. + if m.state.FileName != "" && !strings.ContainsAny(m.state.FileName, `/\`) && + !strings.Contains(m.state.FileName, "%(") && m.state.FileName != ".." { options["output"] = m.state.FileName } if m.state.HTTPUsername != "" {