Pterodactyl is a widely used open-source game server management panel hosting game servers for thousands of gaming communities. Key assessment areas: APP_KEY in the .env file enables Laravel session cookie forgery to impersonate any user including administrators; the application API key grants access to all user accounts and server configurations; Wings daemon node tokens allow direct server file access; and MySQL stores all user credentials and server details accessible with the database password. This guide covers systematic Pterodactyl security assessment.
# Pterodactyl — APP_KEY extraction and Laravel session forgery
PT_URL="https://panel.example.com"
# .env file — Pterodactyl environment configuration
cat /var/www/pterodactyl/.env 2>/dev/null | grep -v "^#" | grep -v "^$" | head -30
# APP_KEY=base64:... <-- Laravel application key (session signing)
# DB_DATABASE=panel <-- MySQL database name
# DB_USERNAME=pterodactyl <-- MySQL username
# DB_PASSWORD=... <-- MySQL password
# REDIS_PASSWORD=... <-- Redis password
# MAIL_PASSWORD=... <-- SMTP password
# APP_KEY — Laravel encryption key used to sign and encrypt session cookies
# With this key, forge a session for the admin user (ID 1)
APP_KEY="base64:your-extracted-key"
# Decrypt existing session cookie to understand format
python3 -c "
import base64, json, os, hmac, hashlib
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
app_key = base64.b64decode('${APP_KEY}'.replace('base64:',''))
# Session cookies are encrypted with AES-256-CBC
# Payload format: {iv: base64, value: base64, mac: hmac-sha256}
print(f'APP_KEY length: {len(app_key)} bytes')
print(f'Laravel session cookie forgery possible')
" 2>/dev/null
# MySQL — extract all user credentials
DB_PASS="extracted-db-password"
mysql -u pterodactyl -p"${DB_PASS}" panel 2>/dev/null << 'EOF'
SELECT id, email, name_first, name_last, password,
root_admin, use_totp
FROM users
ORDER BY root_admin DESC
LIMIT 20;
-- password: bcrypt hashes
-- root_admin: 1 = administrator
-- use_totp: 1 = 2FA enabled
EOF
# Pterodactyl admin API key — user and server enumeration
PT_URL="https://panel.example.com"
ADMIN_API_KEY="ptla_your-admin-api-key" # from MySQL api_keys table or .env
# API keys stored in MySQL
DB_PASS="extracted-db-password"
mysql -u pterodactyl -p"${DB_PASS}" panel 2>/dev/null << 'EOF'
SELECT ak.token, ak.memo, ak.key_type,
u.email, u.root_admin
FROM api_keys ak
JOIN users u ON ak.user_id = u.id
WHERE ak.key_type = 1 -- application keys
LIMIT 10;
EOF
# Application API — list all users (requires admin API key)
curl -s "${PT_URL}/api/application/users?per_page=100" \
-H "Authorization: Bearer ${ADMIN_API_KEY}" \
-H "Content-Type: application/json" \
-H "Accept: application/json" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Total users: {d.get(\"meta\",{}).get(\"pagination\",{}).get(\"total\")}')
for u in d.get('data',[])[:10]:
a = u.get('attributes',{})
print(f' [{a.get(\"id\")}] {a.get(\"email\")} admin={a.get(\"root_admin\")}')
" 2>/dev/null
# Application API — list all game servers
curl -s "${PT_URL}/api/application/servers?per_page=50" \
-H "Authorization: Bearer ${ADMIN_API_KEY}" \
-H "Accept: application/json" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Total servers: {d.get(\"meta\",{}).get(\"pagination\",{}).get(\"total\")}')
for s in d.get('data',[])[:10]:
a = s.get('attributes',{})
print(f' [{a.get(\"id\")}] {a.get(\"name\")} UUID={a.get(\"uuid\")}')
print(f' node={a.get(\"node\")} status={a.get(\"status\")}')
" 2>/dev/null
# Pterodactyl Wings daemon — node token and server file access
# Wings configuration — node token for authentication
cat /etc/pterodactyl/config.yml 2>/dev/null | grep -E "token|api|secret" | head -10
# token: ptlc_... <-- node authentication token for panel communication
# api.token: ... <-- API token used by Wings to authenticate to panel
# Wings API — file listing (requires authentication)
WINGS_URL="https://node.example.com:8443"
NODE_TOKEN="ptlc_your-node-token"
SERVER_UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
curl -s "${WINGS_URL}/api/servers/${SERVER_UUID}/files/list-directory?directory=/" \
-H "Authorization: Bearer ${NODE_TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
for f in d.get('files',d)[:20]:
if isinstance(f, dict):
print(f' {f.get(\"name\")} mode={f.get(\"mode\")} size={f.get(\"size\")}')
" 2>/dev/null
# Wings file read — read server configuration files
curl -s "${WINGS_URL}/api/servers/${SERVER_UUID}/files/contents?file=/server.properties" \
-H "Authorization: Bearer ${NODE_TOKEN}" 2>/dev/null | head -20
# server.properties may contain RCON password, admin password
# .env files in game server may contain API keys
# config files may contain database credentials
# SFTP — Pterodactyl provides SFTP access to each game server
# SFTP port: default 2022 (or per-node configuration)
# Username: username.server-uuid
# Password: Pterodactyl account password
ssh -p 2022 admin.${SERVER_UUID}@node.example.com 2>/dev/null
# SFTP access allows reading all server files including configs
| Security Test | Method | Risk |
|---|---|---|
| APP_KEY extraction and Laravel session cookie forgery | Read .env APP_KEY — forge Laravel session cookies for any user account including root administrators; bypass 2FA; generate valid password reset tokens | Critical |
| MySQL DB_PASSWORD extraction — all user credentials | Read .env DB_PASSWORD — MySQL users table with all bcrypt password hashes and admin status; api_keys table with all application and client API keys | Critical |
| Admin API key enumeration — all users and servers | GET /api/application/users and /api/application/servers with admin API key — all user emails, admin flags, 2FA status; all server UUIDs and configurations | High |
| Wings node token extraction — server file access | Read /etc/pterodactyl/config.yml — Wings node token; Wings API file listing and reading for all game servers on the node including sensitive server.properties and plugin configs | High |
| Game server SFTP — server config and credential access | SFTP port 2022 with Pterodactyl credentials — all game server files including RCON passwords, Discord bot tokens, plugin database credentials, and mod API keys | Medium |
Ironimo tests Pterodactyl deployments for .env APP_KEY extraction and Laravel session cookie forgery, DB_PASSWORD MySQL credential disclosure, admin API key enumeration via /api/application/users and /api/application/servers, Wings /etc/pterodactyl/config.yml node token extraction, Wings API server file listing and reading, MySQL api_keys table enumeration, SFTP game server file access assessment, MAIL_PASSWORD SMTP credential exposure, REDIS_PASSWORD Redis access, and root_admin account 2FA enforcement verification.
Start free scan