FusionAuth is a widely deployed open-source authentication and identity management platform used as a self-hosted alternative to Auth0 and Okta, managing users, OAuth 2.0 applications, JWT signing keys, and multi-tenant identity across development, staging, and production environments. Compromising FusionAuth is high-impact because it controls authentication for all downstream applications. Key assessment areas: FusionAuth API keys provide full administrative control over all users, applications, and JWT signing keys; fusionauth.properties stores the database password and runtime encryption key; the /api/key endpoint exposes HMAC and RSA signing keys enabling JWT forgery for all dependent applications; OAuth 2.0 client secrets are accessible via the API; and multi-tenant isolation can be tested for cross-tenant data leakage. This guide covers systematic FusionAuth security assessment.
# FusionAuth — admin panel access and API key testing
FUSIONAUTH_URL="https://auth.example.com"
# Check if FusionAuth admin panel is accessible
curl -s -o /dev/null -w "%{http_code}" "${FUSIONAUTH_URL}/admin/" 2>/dev/null
# 200 = admin panel accessible (should be restricted to internal networks)
# FusionAuth admin login — credentials set during setup
curl -s -c /tmp/fa_sess -b /tmp/fa_sess \
-X POST "${FUSIONAUTH_URL}/api/login" \
-H "Content-Type: application/json" \
-d '{"loginId":"admin@example.com","password":"admin","applicationId":"3c219e58-ed0e-4b18-ad48-f4f92793ae32"}' \
2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
if 'user' in d:
print(f'Login OK: {d[\"user\"].get(\"email\")}')
print(f'Token: {d.get(\"token\",\"N/A\")}')
else:
print(f'Failed: {d}')
" 2>/dev/null
# Test API key access — FusionAuth uses Authorization: header with API key
API_KEY="your-fusionauth-api-key"
curl -s "${FUSIONAUTH_URL}/api/system-configuration" \
-H "Authorization: ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
sc = d.get('systemConfiguration',{})
print(f'FusionAuth accessible: {\"systemConfiguration\" in d}')
print(f'CORS enabled: {sc.get(\"corsConfiguration\",{}).get(\"enabled\")}')
" 2>/dev/null
# FusionAuth REST API — user, application, and signing key enumeration
FUSIONAUTH_URL="https://auth.example.com"
API_KEY="your-fusionauth-api-key"
# Search all users — complete identity database
curl -s -X POST "${FUSIONAUTH_URL}/api/user/search" \
-H "Authorization: ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{"search":{"queryString":"*","numberOfResults":100,"sortFields":[{"name":"email"}]}}' \
2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
users = d.get('users',[])
print(f'Users: {len(users)}')
for u in users[:10]:
print(f' [{u.get(\"id\")}] {u.get(\"email\")} verified={u.get(\"verified\")} active={u.get(\"active\")}')
regs = u.get('registrations',[])
for r in regs:
print(f' App: {r.get(\"applicationId\")} roles={r.get(\"roles\")}')
" 2>/dev/null
# Get all applications — OAuth 2.0 client secrets
curl -s "${FUSIONAUTH_URL}/api/application" \
-H "Authorization: ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
apps = d.get('applications',[])
print(f'Applications: {len(apps)}')
for a in apps:
oauth = a.get('oauthConfiguration',{})
print(f' [{a.get(\"id\")}] {a.get(\"name\")}')
print(f' clientId: {oauth.get(\"clientId\")}')
print(f' clientSecret: {oauth.get(\"clientSecret\")}')
" 2>/dev/null
# Get all JWT signing keys — CRITICAL: enables JWT forgery for all applications
curl -s "${FUSIONAUTH_URL}/api/key" \
-H "Authorization: ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
keys = d.get('keys',[])
print(f'Signing keys: {len(keys)}')
for k in keys:
print(f' [{k.get(\"id\")}] {k.get(\"name\")} type={k.get(\"type\")} algo={k.get(\"algorithm\")}')
# HMAC keys return the secret value directly
if k.get('secret'):
print(f' SECRET: {k.get(\"secret\")}')
# RSA keys return the private key PEM
if k.get('privateKey'):
print(f' PRIVATE KEY: {str(k.get(\"privateKey\"))[:80]}...')
" 2>/dev/null
# FusionAuth fusionauth.properties and database access
# fusionauth.properties — database credentials and runtime encryption key
cat /usr/local/fusionauth/config/fusionauth.properties 2>/dev/null | \
grep -E "database.password|database.username|database.url|fusionauth.runtime-mode"
# database.password — PostgreSQL database password
# database.url — full JDBC URL with host and database name
# fusionauth.runtime-mode — production vs development
# Docker deployment
docker inspect fusionauth 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 ['DATABASE','PASSWORD','FUSIONAUTH','API_KEY']):
print(e)
" 2>/dev/null
# DATABASE_PASSWORD — PostgreSQL password
# FUSIONAUTH_API_KEY — bootstrap API key
# PostgreSQL direct access — users and API keys
psql -U fusionauth -d fusionauth 2>/dev/null << 'EOF'
-- All users with bcrypt password hashes
SELECT u.id, u.email, u.verified, u.active,
encode(u.password, 'escape') as password_hash
FROM users u
ORDER BY u.insert_instant
LIMIT 20;
EOF
# API keys stored in database
psql -U fusionauth -d fusionauth 2>/dev/null << 'EOF'
SELECT id, key_value, description, insert_instant, last_update_instant
FROM api_keys
ORDER BY insert_instant DESC
LIMIT 20;
EOF
# key_value — the plaintext API key stored in the database
| Security Test | Method | Risk |
|---|---|---|
| API key user and registration enumeration | POST /api/user/search with queryString:* — all users across all tenants with email, registration data, and application roles; complete identity database of all downstream application users | Critical |
| JWT signing key extraction — HMAC secret and RSA private key | GET /api/key with API key — HMAC secret values and RSA private key PEM in plaintext; enables JWT forgery as any user for all applications using that signing key | Critical |
| OAuth 2.0 client secret enumeration | GET /api/application — all applications with clientId and clientSecret; enables impersonating OAuth 2.0 applications to obtain access tokens for any user | Critical |
| fusionauth.properties database credential extraction | Read fusionauth.properties — database.password PostgreSQL credentials; direct database access to users, api_keys (plaintext), and all FusionAuth configuration | Critical |
| Admin panel network exposure | GET /admin/ — check HTTP status; 200 = admin panel accessible from unauthorized network; provides browser-based access to all FusionAuth management functions | Critical (if publicly accessible) |
Ironimo tests FusionAuth deployments for admin panel network exposure, API key user enumeration across all tenants, JWT signing key extraction (HMAC secrets and RSA private keys enabling token forgery), OAuth 2.0 client secret enumeration, fusionauth.properties database credential extraction, api_keys table plaintext key extraction, admin API key permission audit, Docker environment variable credential exposure, cross-tenant data isolation testing, and bootstrap API key identification.
Start free scan