Tautulli is one of the most widely deployed self-hosted Plex analytics and notification applications, collecting detailed viewing statistics for all Plex users and sending notifications when streams start or stop. Its security profile is significant for two reasons: the Plex authentication token it stores gives full Plex Media Server API access, and it accumulates detailed behavioral data on all users. Its security assessment covers: Tautulli's REST API accepts an API key configured in Settings > Web Interface — this key provides read access to all viewing history, user statistics, and notification configurations; Tautulli stores the Plex owner's X-Plex-Token in its config.ini configuration file — this token provides full Plex API access including library management and user administration; Tautulli's notification agent webhooks make outbound HTTP POST requests to configured URLs on Plex events — webhook URLs targeting internal services create an SSRF vector; and Tautulli's get_history API endpoint returns the complete viewing history for all users including IP addresses, device information, and watch duration. This guide covers systematic Tautulli security assessment.
# Tautulli API — single API key controls all read/write operations
TAUTULLI_URL="https://tautulli.example.com"
API_KEY="your-tautulli-api-key"
# Get all users on the Plex server
curl -s "${TAUTULLI_URL}/api/v2?apikey=${API_KEY}&cmd=get_users" \
2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
users = d.get('response',{}).get('data',{}).get('data',[])
print(f'Plex users: {len(users)}')
for u in users:
print(f' {u.get(\"username\")} ({u.get(\"email\",\"?\")}) shared_libraries={len(u.get(\"shared_libraries\",[]))}')
" 2>/dev/null
# Get full viewing history for all users
curl -s "${TAUTULLI_URL}/api/v2?apikey=${API_KEY}&cmd=get_history&length=100" \
2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
history = d.get('response',{}).get('data',{}).get('data',[])
print(f'History entries: {len(history)}')
for h in history[:10]:
print(f' {h.get(\"user\")} watched {h.get(\"full_title\")} from {h.get(\"ip_address\")} on {h.get(\"player\")}')
" 2>/dev/null
# Get server statistics and library info
curl -s "${TAUTULLI_URL}/api/v2?apikey=${API_KEY}&cmd=get_libraries" \
2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
libs = d.get('response',{}).get('data',[])
print(f'Libraries: {len(libs)}')
for l in libs:
print(f' {l.get(\"section_name\")} type={l.get(\"section_type\")} count={l.get(\"count\")}')
" 2>/dev/null
# Tautulli config.ini — stores Plex authentication token in plaintext
# The plex_token grants full Plex Media Server API access
# If you have filesystem access to the Tautulli config directory
grep "plex_token" /path/to/tautulli/config/config.ini 2>/dev/null
# Alternatively, extract via Tautulli API
API_KEY="your-tautulli-api-key"
TAUTULLI_URL="https://tautulli.example.com"
curl -s "${TAUTULLI_URL}/api/v2?apikey=${API_KEY}&cmd=get_server_info" \
2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
server = d.get('response',{}).get('data',{})
print(f'Plex server: {server.get(\"pms_name\")}')
print(f'Version: {server.get(\"pms_version\")}')
print(f'Plex token (if exposed): {server.get(\"pms_token\",\"not in response\")}')
" 2>/dev/null
# With a Plex token, access the Plex Media Server API directly
PLEX_TOKEN="extracted-plex-token"
PLEX_URL="http://localhost:32400"
curl -s "${PLEX_URL}/library/sections?X-Plex-Token=${PLEX_TOKEN}" 2>/dev/null | head -20
| Security Test | Method | Risk |
|---|---|---|
| API key access to complete Plex viewing history | GET /api/v2?apikey=KEY&cmd=get_history — returns complete viewing history for all Plex users including username, IP address, device, content watched, and watch duration | High |
| Plex token in config.ini giving full Plex API access | Read /config/config.ini plex_token field — token provides full Plex Media Server API access including library management, user administration, and stream control | Critical |
| Notification webhook SSRF on Plex stream events | Configure webhook URL to internal address — Tautulli server makes outbound POST to webhook URL on every Plex stream start/stop event; any Plex user starting a stream can trigger the SSRF | High |
| All Plex user enumeration via API | GET /api/v2?apikey=KEY&cmd=get_users — lists all Plex users with usernames, emails, and shared library access for the entire Plex server | High |
| Unauthenticated web interface access | GET / without credentials — full Tautulli web UI accessible without login when HTTP_AUTH not configured; all dashboards and history data viewable | High |
| Notification agent credential extraction | GET /api/v2?apikey=KEY&cmd=get_notifiers — lists all notification agents; some return stored credentials (SMTP password, webhook URLs with embedded tokens) in the response | Medium |
Ironimo tests Tautulli deployments for API key access exposing complete Plex viewing history for all users including IP addresses and device information, Plex authentication token extraction from config.ini giving full Plex Media Server API access, notification webhook SSRF triggered by Plex stream events pointing to internal services, all Plex user enumeration via the API, unauthenticated web interface access, and notification agent credential extraction.
Start free scan