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