Package: release.debian.org
Severity: normal
X-Debbugs-Cc: qbittorr...@packages.debian.org
Control: affects -1 + src:qbittorrent
User: release.debian....@packages.debian.org
Usertags: unblock

Please unblock package qbittorrent

Package not yet uploaded.

To fix bug #1108843 with security issue (no DSA yet)

I've two choices: backport 2 patches from 5.1.2 or release the 5.1.2
version over 5.1.0

debdiff at the bottom.

What is your opinion?

Christian

$ cat qbittorrent_5.1.0-2.debdiff
diff -Nru qbittorrent-5.1.0/debian/changelog qbittorrent-5.1.0/debian/changelog
--- qbittorrent-5.1.0/debian/changelog  2025-04-28 09:24:06.000000000 +0200
+++ qbittorrent-5.1.0/debian/changelog  2025-07-06 16:40:13.000000000 +0200
@@ -1,3 +1,10 @@
+qbittorrent (5.1.0-2) unstable; urgency=medium
+
+  * Add two patches from 5.1.2 version to fix security issues: WebAPI, Rss
+    and Search modules (Closes: #1108843)
+
+ -- Christian Marillat <maril...@debian.org>  Sun, 06 Jul 2025 16:40:13 +0200
+
 qbittorrent (5.1.0-1) unstable; urgency=medium
 
   * New upstream release.
diff -Nru 
qbittorrent-5.1.0/debian/patches/4f94eac235cefa8b83489cb3135dad87fcbed1e3.patch 
qbittorrent-5.1.0/debian/patches/4f94eac235cefa8b83489cb3135dad87fcbed1e3.patch
--- 
qbittorrent-5.1.0/debian/patches/4f94eac235cefa8b83489cb3135dad87fcbed1e3.patch 
    1970-01-01 01:00:00.000000000 +0100
+++ 
qbittorrent-5.1.0/debian/patches/4f94eac235cefa8b83489cb3135dad87fcbed1e3.patch 
    2025-07-06 16:39:40.000000000 +0200
@@ -0,0 +1,191 @@
+From d379fa30350bd2aaf50656c7cd5fbaf6f6219773 Mon Sep 17 00:00:00 2001
+From: "Vladimir Golovnev (Glassez)" <glas...@yandex.ru>
+Date: Mon, 23 Jun 2025 13:14:37 +0300
+Subject: [PATCH 1/2] Prevent opening local files if web page is expected
+
+---
+ src/base/rss/rss_article.cpp       | 20 ++++++++++----------
+ src/gui/rss/rsswidget.cpp          |  4 ++--
+ src/gui/search/searchjobwidget.cpp |  8 ++++----
+ 3 files changed, 16 insertions(+), 16 deletions(-)
+
+--- a/src/base/rss/rss_article.cpp
++++ b/src/base/rss/rss_article.cpp
+@@ -48,16 +48,16 @@ const QString Article::KeyIsRead = u"isR
+ 
+ Article::Article(Feed *feed, const QVariantHash &varHash)
+     : QObject(feed)
+-    , m_feed(feed)
+-    , m_guid(varHash.value(KeyId).toString())
+-    , m_date(varHash.value(KeyDate).toDateTime())
+-    , m_title(varHash.value(KeyTitle).toString())
+-    , m_author(varHash.value(KeyAuthor).toString())
+-    , m_description(varHash.value(KeyDescription).toString())
+-    , m_torrentURL(varHash.value(KeyTorrentURL).toString())
+-    , m_link(varHash.value(KeyLink).toString())
+-    , m_isRead(varHash.value(KeyIsRead, false).toBool())
+-    , m_data(varHash)
++    , m_feed {feed}
++    , m_guid {varHash.value(KeyId).toString()}
++    , m_date {varHash.value(KeyDate).toDateTime()}
++    , m_title {varHash.value(KeyTitle).toString()}
++    , m_author {varHash.value(KeyAuthor).toString()}
++    , m_description {varHash.value(KeyDescription).toString()}
++    , m_torrentURL {varHash.value(KeyTorrentURL).toString()}
++    , m_link {varHash.value(KeyLink).toString()}
++    , m_isRead {varHash.value(KeyIsRead, false).toBool()}
++    , m_data {varHash}
+ {
+ }
+ 
+--- a/src/gui/rss/rsswidget.cpp
++++ b/src/gui/rss/rsswidget.cpp
+@@ -40,6 +40,7 @@
+ #include <QString>
+ 
+ #include "base/global.h"
++#include "base/logger.h"
+ #include "base/net/downloadmanager.h"
+ #include "base/preferences.h"
+ #include "base/rss/rss_article.h"
+@@ -415,16 +416,52 @@ void RSSWidget::downloadSelectedTorrents
+ // open the url of the selected RSS articles in the Web browser
+ void RSSWidget::openSelectedArticlesUrls()
+ {
++    qsizetype emptyLinkCount = 0;
++    qsizetype badLinkCount = 0;
++    QString articleTitle;
+     for (QListWidgetItem *item : 
asConst(m_ui->articleListWidget->selectedItems()))
+     {
+         auto *article = item->data(Qt::UserRole).value<RSS::Article *>();
+         Q_ASSERT(article);
+ 
+-        // Mark as read
+         article->markAsRead();
+ 
+-        if (!article->link().isEmpty())
+-            QDesktopServices::openUrl(QUrl(article->link()));
++        const QString articleLink = article->link();
++        const QUrl articleLinkURL {articleLink};
++        if (articleLinkURL.isEmpty()) [[unlikely]]
++        {
++            if (articleTitle.isEmpty())
++                articleTitle = article->title();
++            ++emptyLinkCount;
++        }
++        else if (articleLinkURL.isLocalFile()) [[unlikely]]
++        {
++            if (badLinkCount == 0)
++                articleTitle = article->title();
++            ++badLinkCount;
++
++            LogMsg(tr("Blocked opening RSS article URL. URL pointing to local 
file might be malicious behaviour. Article: \"%1\". URL: \"%2\".")
++                    .arg(article->title(), articleLink), Log::WARNING);
++        }
++        else [[likely]]
++        {
++            QDesktopServices::openUrl(articleLinkURL);
++        }
++    }
++
++    if (badLinkCount > 0)
++    {
++        QString message = tr("Blocked opening RSS article URL. The following 
article URL is pointing to local file and it may be malicious 
behaviour:\n%1").arg(articleTitle);
++        if (badLinkCount > 1)
++            message.append(u"\n" + tr("There are %1 more articles with the 
same issue.").arg(badLinkCount - 1));
++        QMessageBox::warning(this, u"qBittorrent"_s, message, 
QMessageBox::Ok);
++    }
++    else if (emptyLinkCount > 0)
++    {
++        QString message = tr("The following article has no news URL 
provided:\n%1").arg(articleTitle);
++        if (emptyLinkCount > 1)
++            message.append(u"\n" + tr("There are %1 more articles with the 
same issue.").arg(emptyLinkCount - 1));
++        QMessageBox::warning(this, u"qBittorrent"_s, message, 
QMessageBox::Ok);
+     }
+ }
+ 
+--- a/src/gui/search/searchjobwidget.cpp
++++ b/src/gui/search/searchjobwidget.cpp
+@@ -35,10 +35,12 @@
+ #include <QHeaderView>
+ #include <QKeyEvent>
+ #include <QMenu>
++#include <QMessageBox>
+ #include <QPalette>
+ #include <QStandardItemModel>
+ #include <QUrl>
+ 
++#include "base/logger.h"
+ #include "base/preferences.h"
+ #include "base/search/searchdownloadhandler.h"
+ #include "base/search/searchhandler.h"
+@@ -319,15 +321,52 @@ void SearchJobWidget::downloadTorrents(c
+         downloadTorrent(rowIndex, option);
+ }
+ 
+-void SearchJobWidget::openTorrentPages() const
++void SearchJobWidget::openTorrentPages()
+ {
+-    const QModelIndexList rows 
{m_ui->resultsBrowser->selectionModel()->selectedRows()};
++    const QModelIndexList rows = 
m_ui->resultsBrowser->selectionModel()->selectedRows();
++    qsizetype emptyLinkCount = 0;
++    qsizetype badLinkCount = 0;
++    QString warningEntryName;
+     for (const QModelIndex &rowIndex : rows)
+     {
+-        const QString descrLink = m_proxyModel->data(
+-                    m_proxyModel->index(rowIndex.row(), 
SearchSortModel::DESC_LINK)).toString();
+-        if (!descrLink.isEmpty())
+-            QDesktopServices::openUrl(QUrl::fromEncoded(descrLink.toUtf8()));
++        const QString entryName = m_proxyModel->index(rowIndex.row(), 
SearchSortModel::NAME).data().toString();
++        const QString descrLink = m_proxyModel->index(rowIndex.row(), 
SearchSortModel::DESC_LINK).data().toString();
++
++        const QUrl descrLinkURL {descrLink};
++        if (descrLinkURL.isEmpty()) [[unlikely]]
++        {
++            if (warningEntryName.isEmpty())
++                warningEntryName = entryName;
++            ++emptyLinkCount;
++        }
++        else if (descrLinkURL.isLocalFile()) [[unlikely]]
++        {
++            if (badLinkCount == 0)
++                warningEntryName = entryName;
++            ++badLinkCount;
++
++            LogMsg(tr("Blocked opening search result description page URL. 
URL pointing to local file might be malicious behaviour. Name: \"%1\". URL: 
\"%2\".")
++                    .arg(entryName, descrLink), Log::WARNING);
++        }
++        else [[likely]]
++        {
++            QDesktopServices::openUrl(descrLinkURL);
++        }
++    }
++
++    if (badLinkCount > 0)
++    {
++        QString message = tr("Blocked opening search result description page 
URL. The following result URL is pointing to local file and it may be malicious 
behaviour:\n%1").arg(warningEntryName);
++        if (badLinkCount > 1)
++            message.append(u"\n" + tr("There are %1 more results with the 
same issue.").arg(badLinkCount - 1));
++        QMessageBox::warning(this, u"qBittorrent"_s, message, 
QMessageBox::Ok);
++    }
++    else if (emptyLinkCount > 0)
++    {
++        QString message = tr("Entry \"%1\" has no description page URL 
provided.").arg(warningEntryName);
++        if (emptyLinkCount > 1)
++            message.append(u"\n" + tr("There are %1 more entries with the 
same issue.").arg(emptyLinkCount - 1));
++        QMessageBox::warning(this, u"qBittorrent"_s, message, 
QMessageBox::Ok);
+     }
+ }
+ 
+--- a/src/gui/search/searchjobwidget.h
++++ b/src/gui/search/searchjobwidget.h
+@@ -127,7 +127,7 @@ private:
+     void onUIThemeChanged();
+ 
+     void downloadTorrents(AddTorrentOption option = 
AddTorrentOption::Default);
+-    void openTorrentPages() const;
++    void openTorrentPages();
+     void copyTorrentURLs() const;
+     void copyTorrentDownloadLinks() const;
+     void copyTorrentNames() const;
diff -Nru 
qbittorrent-5.1.0/debian/patches/9b29d37d210f28f46eb4758611d7b06f4603b9d1.patch 
qbittorrent-5.1.0/debian/patches/9b29d37d210f28f46eb4758611d7b06f4603b9d1.patch
--- 
qbittorrent-5.1.0/debian/patches/9b29d37d210f28f46eb4758611d7b06f4603b9d1.patch 
    1970-01-01 01:00:00.000000000 +0100
+++ 
qbittorrent-5.1.0/debian/patches/9b29d37d210f28f46eb4758611d7b06f4603b9d1.patch 
    2025-07-06 16:39:44.000000000 +0200
@@ -0,0 +1,37 @@
+From 9b29d37d210f28f46eb4758611d7b06f4603b9d1 Mon Sep 17 00:00:00 2001
+From: Chocobo1 <choco...@users.noreply.github.com>
+Date: Mon, 30 Jun 2025 01:39:03 +0800
+Subject: [PATCH] WebAPI: Trim leading whitespaces on Run External Program
+ fields
+
+Hacked qbt instances may contain malicious script placed in Run External 
Program and the script
+will attempt to hide itself by adding a lot whitespaces at the start of the 
command string.
+Users may mistake the field of being empty but is actually not.
+So trim the leading whitespaces to easily expose the malicious script.
+
+Note that GUI already trim the fields and only WebAPI doesn't trim them. This 
patch will unify
+the behavior.
+Related: 
https://github.com/qbittorrent/docker-qbittorrent-nox/issues/71#issuecomment-2993567440
+
+PR #22939.
+---
+ src/webui/api/appcontroller.cpp | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/src/webui/api/appcontroller.cpp
++++ b/src/webui/api/appcontroller.cpp
+@@ -673,12 +673,12 @@ void AppController::setPreferencesAction
+     if (hasKey(u"autorun_on_torrent_added_enabled"_s))
+         pref->setAutoRunOnTorrentAddedEnabled(it.value().toBool());
+     if (hasKey(u"autorun_on_torrent_added_program"_s))
+-        pref->setAutoRunOnTorrentAddedProgram(it.value().toString());
++        
pref->setAutoRunOnTorrentAddedProgram(it.value().toString().trimmed());
+     // Run an external program on torrent finished
+     if (hasKey(u"autorun_enabled"_s))
+         pref->setAutoRunOnTorrentFinishedEnabled(it.value().toBool());
+     if (hasKey(u"autorun_program"_s))
+-        pref->setAutoRunOnTorrentFinishedProgram(it.value().toString());
++        
pref->setAutoRunOnTorrentFinishedProgram(it.value().toString().trimmed());
+ 
+     // Connection
+     // Listening Port
diff -Nru qbittorrent-5.1.0/debian/patches/series 
qbittorrent-5.1.0/debian/patches/series
--- qbittorrent-5.1.0/debian/patches/series     1970-01-01 01:00:00.000000000 
+0100
+++ qbittorrent-5.1.0/debian/patches/series     2025-07-06 16:39:32.000000000 
+0200
@@ -0,0 +1,2 @@
+4f94eac235cefa8b83489cb3135dad87fcbed1e3.patch
+9b29d37d210f28f46eb4758611d7b06f4603b9d1.patch
diff -Nru qbittorrent-5.1.0/debian/changelog qbittorrent-5.1.0/debian/changelog
--- qbittorrent-5.1.0/debian/changelog  2025-04-28 09:24:06.000000000 +0200
+++ qbittorrent-5.1.0/debian/changelog  2025-07-06 16:40:13.000000000 +0200
@@ -1,3 +1,10 @@
+qbittorrent (5.1.0-2) unstable; urgency=medium
+
+  * Add two patches from 5.1.2 version to fix security issues: WebAPI, Rss
+    and Search modules (Closes: #1108843)
+
+ -- Christian Marillat <maril...@debian.org>  Sun, 06 Jul 2025 16:40:13 +0200
+
 qbittorrent (5.1.0-1) unstable; urgency=medium
 
   * New upstream release.
diff -Nru 
qbittorrent-5.1.0/debian/patches/4f94eac235cefa8b83489cb3135dad87fcbed1e3.patch 
qbittorrent-5.1.0/debian/patches/4f94eac235cefa8b83489cb3135dad87fcbed1e3.patch
--- 
qbittorrent-5.1.0/debian/patches/4f94eac235cefa8b83489cb3135dad87fcbed1e3.patch 
    1970-01-01 01:00:00.000000000 +0100
+++ 
qbittorrent-5.1.0/debian/patches/4f94eac235cefa8b83489cb3135dad87fcbed1e3.patch 
    2025-07-06 16:39:40.000000000 +0200
@@ -0,0 +1,191 @@
+From d379fa30350bd2aaf50656c7cd5fbaf6f6219773 Mon Sep 17 00:00:00 2001
+From: "Vladimir Golovnev (Glassez)" <glas...@yandex.ru>
+Date: Mon, 23 Jun 2025 13:14:37 +0300
+Subject: [PATCH 1/2] Prevent opening local files if web page is expected
+
+---
+ src/base/rss/rss_article.cpp       | 20 ++++++++++----------
+ src/gui/rss/rsswidget.cpp          |  4 ++--
+ src/gui/search/searchjobwidget.cpp |  8 ++++----
+ 3 files changed, 16 insertions(+), 16 deletions(-)
+
+--- a/src/base/rss/rss_article.cpp
++++ b/src/base/rss/rss_article.cpp
+@@ -48,16 +48,16 @@ const QString Article::KeyIsRead = u"isR
+ 
+ Article::Article(Feed *feed, const QVariantHash &varHash)
+     : QObject(feed)
+-    , m_feed(feed)
+-    , m_guid(varHash.value(KeyId).toString())
+-    , m_date(varHash.value(KeyDate).toDateTime())
+-    , m_title(varHash.value(KeyTitle).toString())
+-    , m_author(varHash.value(KeyAuthor).toString())
+-    , m_description(varHash.value(KeyDescription).toString())
+-    , m_torrentURL(varHash.value(KeyTorrentURL).toString())
+-    , m_link(varHash.value(KeyLink).toString())
+-    , m_isRead(varHash.value(KeyIsRead, false).toBool())
+-    , m_data(varHash)
++    , m_feed {feed}
++    , m_guid {varHash.value(KeyId).toString()}
++    , m_date {varHash.value(KeyDate).toDateTime()}
++    , m_title {varHash.value(KeyTitle).toString()}
++    , m_author {varHash.value(KeyAuthor).toString()}
++    , m_description {varHash.value(KeyDescription).toString()}
++    , m_torrentURL {varHash.value(KeyTorrentURL).toString()}
++    , m_link {varHash.value(KeyLink).toString()}
++    , m_isRead {varHash.value(KeyIsRead, false).toBool()}
++    , m_data {varHash}
+ {
+ }
+ 
+--- a/src/gui/rss/rsswidget.cpp
++++ b/src/gui/rss/rsswidget.cpp
+@@ -40,6 +40,7 @@
+ #include <QString>
+ 
+ #include "base/global.h"
++#include "base/logger.h"
+ #include "base/net/downloadmanager.h"
+ #include "base/preferences.h"
+ #include "base/rss/rss_article.h"
+@@ -415,16 +416,52 @@ void RSSWidget::downloadSelectedTorrents
+ // open the url of the selected RSS articles in the Web browser
+ void RSSWidget::openSelectedArticlesUrls()
+ {
++    qsizetype emptyLinkCount = 0;
++    qsizetype badLinkCount = 0;
++    QString articleTitle;
+     for (QListWidgetItem *item : 
asConst(m_ui->articleListWidget->selectedItems()))
+     {
+         auto *article = item->data(Qt::UserRole).value<RSS::Article *>();
+         Q_ASSERT(article);
+ 
+-        // Mark as read
+         article->markAsRead();
+ 
+-        if (!article->link().isEmpty())
+-            QDesktopServices::openUrl(QUrl(article->link()));
++        const QString articleLink = article->link();
++        const QUrl articleLinkURL {articleLink};
++        if (articleLinkURL.isEmpty()) [[unlikely]]
++        {
++            if (articleTitle.isEmpty())
++                articleTitle = article->title();
++            ++emptyLinkCount;
++        }
++        else if (articleLinkURL.isLocalFile()) [[unlikely]]
++        {
++            if (badLinkCount == 0)
++                articleTitle = article->title();
++            ++badLinkCount;
++
++            LogMsg(tr("Blocked opening RSS article URL. URL pointing to local 
file might be malicious behaviour. Article: \"%1\". URL: \"%2\".")
++                    .arg(article->title(), articleLink), Log::WARNING);
++        }
++        else [[likely]]
++        {
++            QDesktopServices::openUrl(articleLinkURL);
++        }
++    }
++
++    if (badLinkCount > 0)
++    {
++        QString message = tr("Blocked opening RSS article URL. The following 
article URL is pointing to local file and it may be malicious 
behaviour:\n%1").arg(articleTitle);
++        if (badLinkCount > 1)
++            message.append(u"\n" + tr("There are %1 more articles with the 
same issue.").arg(badLinkCount - 1));
++        QMessageBox::warning(this, u"qBittorrent"_s, message, 
QMessageBox::Ok);
++    }
++    else if (emptyLinkCount > 0)
++    {
++        QString message = tr("The following article has no news URL 
provided:\n%1").arg(articleTitle);
++        if (emptyLinkCount > 1)
++            message.append(u"\n" + tr("There are %1 more articles with the 
same issue.").arg(emptyLinkCount - 1));
++        QMessageBox::warning(this, u"qBittorrent"_s, message, 
QMessageBox::Ok);
+     }
+ }
+ 
+--- a/src/gui/search/searchjobwidget.cpp
++++ b/src/gui/search/searchjobwidget.cpp
+@@ -35,10 +35,12 @@
+ #include <QHeaderView>
+ #include <QKeyEvent>
+ #include <QMenu>
++#include <QMessageBox>
+ #include <QPalette>
+ #include <QStandardItemModel>
+ #include <QUrl>
+ 
++#include "base/logger.h"
+ #include "base/preferences.h"
+ #include "base/search/searchdownloadhandler.h"
+ #include "base/search/searchhandler.h"
+@@ -319,15 +321,52 @@ void SearchJobWidget::downloadTorrents(c
+         downloadTorrent(rowIndex, option);
+ }
+ 
+-void SearchJobWidget::openTorrentPages() const
++void SearchJobWidget::openTorrentPages()
+ {
+-    const QModelIndexList rows 
{m_ui->resultsBrowser->selectionModel()->selectedRows()};
++    const QModelIndexList rows = 
m_ui->resultsBrowser->selectionModel()->selectedRows();
++    qsizetype emptyLinkCount = 0;
++    qsizetype badLinkCount = 0;
++    QString warningEntryName;
+     for (const QModelIndex &rowIndex : rows)
+     {
+-        const QString descrLink = m_proxyModel->data(
+-                    m_proxyModel->index(rowIndex.row(), 
SearchSortModel::DESC_LINK)).toString();
+-        if (!descrLink.isEmpty())
+-            QDesktopServices::openUrl(QUrl::fromEncoded(descrLink.toUtf8()));
++        const QString entryName = m_proxyModel->index(rowIndex.row(), 
SearchSortModel::NAME).data().toString();
++        const QString descrLink = m_proxyModel->index(rowIndex.row(), 
SearchSortModel::DESC_LINK).data().toString();
++
++        const QUrl descrLinkURL {descrLink};
++        if (descrLinkURL.isEmpty()) [[unlikely]]
++        {
++            if (warningEntryName.isEmpty())
++                warningEntryName = entryName;
++            ++emptyLinkCount;
++        }
++        else if (descrLinkURL.isLocalFile()) [[unlikely]]
++        {
++            if (badLinkCount == 0)
++                warningEntryName = entryName;
++            ++badLinkCount;
++
++            LogMsg(tr("Blocked opening search result description page URL. 
URL pointing to local file might be malicious behaviour. Name: \"%1\". URL: 
\"%2\".")
++                    .arg(entryName, descrLink), Log::WARNING);
++        }
++        else [[likely]]
++        {
++            QDesktopServices::openUrl(descrLinkURL);
++        }
++    }
++
++    if (badLinkCount > 0)
++    {
++        QString message = tr("Blocked opening search result description page 
URL. The following result URL is pointing to local file and it may be malicious 
behaviour:\n%1").arg(warningEntryName);
++        if (badLinkCount > 1)
++            message.append(u"\n" + tr("There are %1 more results with the 
same issue.").arg(badLinkCount - 1));
++        QMessageBox::warning(this, u"qBittorrent"_s, message, 
QMessageBox::Ok);
++    }
++    else if (emptyLinkCount > 0)
++    {
++        QString message = tr("Entry \"%1\" has no description page URL 
provided.").arg(warningEntryName);
++        if (emptyLinkCount > 1)
++            message.append(u"\n" + tr("There are %1 more entries with the 
same issue.").arg(emptyLinkCount - 1));
++        QMessageBox::warning(this, u"qBittorrent"_s, message, 
QMessageBox::Ok);
+     }
+ }
+ 
+--- a/src/gui/search/searchjobwidget.h
++++ b/src/gui/search/searchjobwidget.h
+@@ -127,7 +127,7 @@ private:
+     void onUIThemeChanged();
+ 
+     void downloadTorrents(AddTorrentOption option = 
AddTorrentOption::Default);
+-    void openTorrentPages() const;
++    void openTorrentPages();
+     void copyTorrentURLs() const;
+     void copyTorrentDownloadLinks() const;
+     void copyTorrentNames() const;
diff -Nru 
qbittorrent-5.1.0/debian/patches/9b29d37d210f28f46eb4758611d7b06f4603b9d1.patch 
qbittorrent-5.1.0/debian/patches/9b29d37d210f28f46eb4758611d7b06f4603b9d1.patch
--- 
qbittorrent-5.1.0/debian/patches/9b29d37d210f28f46eb4758611d7b06f4603b9d1.patch 
    1970-01-01 01:00:00.000000000 +0100
+++ 
qbittorrent-5.1.0/debian/patches/9b29d37d210f28f46eb4758611d7b06f4603b9d1.patch 
    2025-07-06 16:39:44.000000000 +0200
@@ -0,0 +1,37 @@
+From 9b29d37d210f28f46eb4758611d7b06f4603b9d1 Mon Sep 17 00:00:00 2001
+From: Chocobo1 <choco...@users.noreply.github.com>
+Date: Mon, 30 Jun 2025 01:39:03 +0800
+Subject: [PATCH] WebAPI: Trim leading whitespaces on Run External Program
+ fields
+
+Hacked qbt instances may contain malicious script placed in Run External 
Program and the script
+will attempt to hide itself by adding a lot whitespaces at the start of the 
command string.
+Users may mistake the field of being empty but is actually not.
+So trim the leading whitespaces to easily expose the malicious script.
+
+Note that GUI already trim the fields and only WebAPI doesn't trim them. This 
patch will unify
+the behavior.
+Related: 
https://github.com/qbittorrent/docker-qbittorrent-nox/issues/71#issuecomment-2993567440
+
+PR #22939.
+---
+ src/webui/api/appcontroller.cpp | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/src/webui/api/appcontroller.cpp
++++ b/src/webui/api/appcontroller.cpp
+@@ -673,12 +673,12 @@ void AppController::setPreferencesAction
+     if (hasKey(u"autorun_on_torrent_added_enabled"_s))
+         pref->setAutoRunOnTorrentAddedEnabled(it.value().toBool());
+     if (hasKey(u"autorun_on_torrent_added_program"_s))
+-        pref->setAutoRunOnTorrentAddedProgram(it.value().toString());
++        
pref->setAutoRunOnTorrentAddedProgram(it.value().toString().trimmed());
+     // Run an external program on torrent finished
+     if (hasKey(u"autorun_enabled"_s))
+         pref->setAutoRunOnTorrentFinishedEnabled(it.value().toBool());
+     if (hasKey(u"autorun_program"_s))
+-        pref->setAutoRunOnTorrentFinishedProgram(it.value().toString());
++        
pref->setAutoRunOnTorrentFinishedProgram(it.value().toString().trimmed());
+ 
+     // Connection
+     // Listening Port
diff -Nru qbittorrent-5.1.0/debian/patches/series 
qbittorrent-5.1.0/debian/patches/series
--- qbittorrent-5.1.0/debian/patches/series     1970-01-01 01:00:00.000000000 
+0100
+++ qbittorrent-5.1.0/debian/patches/series     2025-07-06 16:39:32.000000000 
+0200
@@ -0,0 +1,2 @@
+4f94eac235cefa8b83489cb3135dad87fcbed1e3.patch
+9b29d37d210f28f46eb4758611d7b06f4603b9d1.patch

Reply via email to