Flarum Security Testing: Default Credentials, API Token, Database, and config.php

Flarum is a widely deployed modern open-source forum platform built in PHP with a React-based frontend, used by communities and organizations to run discussion forums. Its JSON:API backend and PHP architecture are the primary security assessment targets. Key assessment areas: Flarum's admin credentials are set during the setup wizard with no enforced complexity; the JSON:API REST API exposes all discussions, posts, and user data including email addresses; config.php stores the MySQL database password; Flarum's admin API token (generated by the installer or admin panel) allows creating users and modifying admin flags; the flarum_access_tokens database table stores user Bearer tokens; and Flarum's extension ecosystem may introduce additional vulnerabilities including file upload paths and custom API endpoints. This guide covers systematic Flarum security assessment.

Table of Contents

  1. Authentication and Default Credential Testing
  2. JSON:API Discussion and User Enumeration
  3. config.php Credentials and Database Access
  4. Flarum Security Hardening

Authentication and Default Credential Testing

# Flarum — authentication and default credential testing
FLARUM_URL="https://forum.example.com"

# Flarum authentication — POST /api/token returns access token
TOKEN_RESPONSE=$(curl -s -X POST "${FLARUM_URL}/api/token" \
  -H "Content-Type: application/json" \
  -d '{"identification":"admin@example.com","password":"admin","remember":true}' 2>/dev/null)

echo "$TOKEN_RESPONSE" | python3 -c "
import json,sys
d=json.load(sys.stdin)
if 'token' in d:
    print(f'Access token: {d[\"token\"]}')
    print(f'User ID: {d.get(\"userId\")}')
else:
    print(f'Auth failed: {d}')
" 2>/dev/null

# Try common admin email/password combinations
for CREDS in "admin@example.com:admin" "admin@forum.example.com:admin" "admin@example.com:password"; do
  EMAIL="${CREDS%:*}"
  PASS="${CREDS#*:}"
  STATUS=$(curl -s -X POST "${FLARUM_URL}/api/token" \
    -H "Content-Type: application/json" \
    -d "{\"identification\":\"${EMAIL}\",\"password\":\"${PASS}\"}" 2>/dev/null | \
    python3 -c "import json,sys; d=json.load(sys.stdin); print('OK' if 'token' in d else 'FAIL')" 2>/dev/null)
  echo "${CREDS}: $STATUS"
done

# Check unauthenticated API access — many Flarum endpoints are public
curl -s "${FLARUM_URL}/api" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print('API version:', d.get('data',{}).get('attributes',{}).get('version','?'))
" 2>/dev/null

JSON:API Discussion and User Enumeration

# Flarum JSON:API — discussion and user enumeration
FLARUM_URL="https://forum.example.com"
ACCESS_TOKEN="your-flarum-access-token"

# Get all discussions (may be public without auth on open forums)
curl -s "${FLARUM_URL}/api/discussions?sort=-createdAt&page[limit]=50" \
  -H "Authorization: Token ${ACCESS_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
data = d.get('data',[])
print(f'Discussions: {len(data)}')
for disc in data[:10]:
    attrs = disc.get('attributes',{})
    print(f'  [{disc.get(\"id\")}] {attrs.get(\"title\")} posts={attrs.get(\"commentCount\")} views={attrs.get(\"viewCount\")}')
" 2>/dev/null

# Get all posts — full forum content
curl -s "${FLARUM_URL}/api/posts?sort=-createdAt&page[limit]=50" \
  -H "Authorization: Token ${ACCESS_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
data = d.get('data',[])
print(f'Posts: {len(data)}')
for p in data[:5]:
    attrs = p.get('attributes',{})
    content = str(attrs.get('content',''))[:100]
    print(f'  [{p.get(\"id\")}] type={attrs.get(\"contentType\")} content={content}')
" 2>/dev/null

# Get all users — email addresses and admin status
curl -s "${FLARUM_URL}/api/users?sort=joinTime&page[limit]=50" \
  -H "Authorization: Token ${ACCESS_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
data = d.get('data',[])
print(f'Users: {len(data)}')
for u in data[:10]:
    attrs = u.get('attributes',{})
    print(f'  [{u.get(\"id\")}] {attrs.get(\"username\")} email={attrs.get(\"email\")} isEmailConfirmed={attrs.get(\"isEmailConfirmed\")}')
    # isAdmin only visible to admin tokens
    if attrs.get('isAdmin') is not None:
        print(f'    isAdmin: {attrs.get(\"isAdmin\")}')
" 2>/dev/null

config.php Credentials and Database Access

# Flarum config.php and database credential extraction

# config.php — MySQL credentials in PHP array
grep -E "password|database|host|username" \
  /var/www/html/flarum/config.php 2>/dev/null
# 'database' => ['driver'=>'mysql', 'host'=>'localhost', 'password'=>'DB_PASSWORD']

# MySQL direct access — user accounts and access tokens
mysql -u flarum -p"DB_PASSWORD" flarum 2>/dev/null << 'EOF'
-- All users with bcrypt hashed passwords
SELECT id, username, email, is_email_confirmed, is_admin,
       joined_at, last_seen_at
FROM flarum_users
ORDER BY is_admin DESC, joined_at
LIMIT 20;
EOF

# flarum_access_tokens — all active Bearer tokens
mysql -u flarum -p"DB_PASSWORD" flarum 2>/dev/null << 'EOF'
SELECT t.id, t.token, t.user_id, u.username, u.email,
       t.type, t.created_at, t.last_activity_at
FROM flarum_access_tokens t
JOIN flarum_users u ON t.user_id = u.id
ORDER BY t.last_activity_at DESC
LIMIT 20;
EOF
# token column contains the plaintext Bearer token value

# Check for installed extensions and their configuration
mysql -u flarum -p"DB_PASSWORD" flarum 2>/dev/null << 'EOF'
SELECT * FROM flarum_settings WHERE key LIKE '%api%' OR key LIKE '%secret%' OR key LIKE '%key%';
EOF

Flarum Security Hardening

Flarum Security Hardening Checklist:
Security TestMethodRisk
Admin credential exploitation and token acquisitionPOST /api/token with admin email and weak password — Bearer token returned; access to all forum data, user accounts, extension management, and admin API endpointsCritical
JSON:API user email enumerationGET /api/users with admin token — all users with email addresses; enables targeted phishing and credential attacks against forum membersHigh
config.php MySQL credential extractionRead config.php database password — direct MySQL access to flarum_users (bcrypt hashes), flarum_access_tokens (plaintext Bearer tokens), and all forum dataCritical
flarum_access_tokens plaintext token extractionMySQL SELECT from flarum_access_tokens — token column contains plaintext Bearer tokens valid for API authentication as any userCritical
Unauthenticated discussion enumeration on public forumsGET /api/discussions without auth — all public discussions and posts accessible; reveals forum content and user activity patterns without authenticationMedium (by design on public forums)

Automate Flarum Security Testing

Ironimo tests Flarum deployments for admin credential exploitation, JSON:API discussion and user enumeration including email address harvesting, config.php MySQL credential extraction, flarum_access_tokens plaintext Bearer token extraction, unauthenticated forum access testing, email enumeration via login error differentiation, extension audit and attack surface assessment, rate limiting verification on /api/token, and flarum_settings sensitive key enumeration.

Start free scan