CryptPad Security Testing: Default Credentials, API Key, Database, and Zero-Knowledge Office

CryptPad is a self-hosted zero-knowledge collaborative office suite — while document content is end-to-end encrypted in the browser, critical server-side infrastructure components can be misconfigured. Key assessment areas: adminKeys in config.js controls admin panel access and must be configured correctly; MongoDB stores user session tokens and account metadata; open registration without invite codes allows unauthorized account creation; and blob storage contains encrypted document files accessible to anyone who knows the blob path. This guide covers systematic CryptPad security assessment.

Table of Contents

  1. Admin Panel Access and adminKeys Configuration
  2. MongoDB Session and Account Metadata Extraction
  3. Config.js Secret Extraction and Instance Assessment
  4. CryptPad Security Hardening

Admin Panel Access and adminKeys Configuration

# CryptPad — admin panel access and adminKeys configuration
CP_URL="https://cryptpad.example.com"

# Admin panel — CryptPad uses Ed25519 public key for admin auth
# /admin accessible only to users whose public key is in config.adminKeys
curl -s -o /dev/null -w "%{http_code}" "${CP_URL}/admin/" 2>/dev/null
# 200 = admin panel accessible (still requires key-based auth)

# /api/config — instance configuration (publicly accessible)
curl -s "${CP_URL}/api/config" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Instance name: {d.get(\"instanceTitle\")}')
print(f'Admin email: {d.get(\"adminEmail\")}')
print(f'Max upload size: {d.get(\"maxUploadSize\")}')
print(f'Registration allowed: {not d.get(\"restrictRegistration\",False)}')
print(f'Storage limit: {d.get(\"defaultStorageMB\")}MB')
# This endpoint reveals whether registration is open
# and the admin contact email
" 2>/dev/null

# /checkup — admin diagnostic page (requires admin key auth in browser)
# But the endpoint itself may reveal server configuration info
curl -s "${CP_URL}/checkup/" 2>/dev/null | head -20

# config.js — CryptPad server configuration (critical secrets)
cat /opt/cryptpad/config/config.js 2>/dev/null | \
  grep -E "adminKeys|httpUnsafeOrigin|adminEmail|blockPath|blobPath|filePath|mongoUri|rpc" \
  | head -20
# adminKeys: ['ed25519-public-key-here'] — admin panel access
# httpUnsafeOrigin: 'http://localhost:3000' — should be HTTPS production URL
# mongoUri: 'mongodb://localhost:27017/cryptpad' — MongoDB connection
# blockPath: '/path/to/block/storage'
# blobPath: '/path/to/blob/storage'

# Docker environment
docker inspect cryptpad 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
for c in d:
    for e in c.get('Config',{}).get('Env',[]):
        if any(k in e for k in ['CPAD_', 'ADMIN', 'MONGO', 'SECRET']):
            print(e)
" 2>/dev/null

MongoDB Session and Account Metadata Extraction

# CryptPad MongoDB session and account metadata extraction

# MongoDB — CryptPad uses MongoDB for session and account data
mongo --host localhost cryptpad 2>/dev/null << 'EOF'
// List all collections
show collections

// Session tokens — active authentication tokens
db.sessions.find({}).limit(10).pretty()
// _id: session ID, token: auth token, user: user hash

// User account data
db.users.find({}).limit(10).pretty()
// _id: user hash, edPublic: Ed25519 public key, created: timestamp

// Registered users count
db.users.count()

// Active sessions
db.sessions.count()
EOF

# Check if MongoDB requires authentication
mongo --host localhost --eval "db.adminCommand({listDatabases:1})" 2>/dev/null
# If this works without password, MongoDB is unauthenticated

# List blob/block storage (encrypted document files)
ls /opt/cryptpad/data/blob/ 2>/dev/null | head -20
ls /opt/cryptpad/data/block/ 2>/dev/null | head -20
# Files are named by hash but are accessible if path is known
# Document content IS encrypted (zero-knowledge)
# But file existence reveals that documents exist

# Get encrypted blob (content is AES-256 encrypted)
BLOB_HASH="abc123def456"  # from URL or leaked path
curl -s "${CP_URL}/blob/${BLOB_HASH:0:2}/${BLOB_HASH}" 2>/dev/null | xxd | head -5
# Returns binary encrypted content (cannot decrypt without user key)
# But access itself may be auditable

Config.js Secret Extraction and Instance Assessment

# CryptPad config.js assessment and instance security checks

# config.js — full configuration
cat /opt/cryptpad/config/config.js 2>/dev/null

# Key configuration items to check:
# 1. httpUnsafeOrigin — should match the public HTTPS URL
#    If set to http:// or localhost, cookie security may be broken
# 2. adminKeys — list of Ed25519 public keys with admin access
#    Empty array = NO admin panel access (locked out)
#    Wrong key = admin panel inaccessible
# 3. maxWorkerCount — performance config (not security)
# 4. restrictRegistration — false = open registration
# 5. allowSubscriptions — Stripe payment integration
# 6. mongoUri — database connection (may include auth credentials)
#    e.g., mongodb://user:password@localhost:27017/cryptpad

python3 -c "
import re, sys
content = open('/opt/cryptpad/config/config.js').read()

# Extract key values
patterns = {
    'adminKeys': r\"adminKeys.*?\\['([^']+)'\]\",
    'mongoUri': r\"mongodb://[^']+\",
    'httpUnsafeOrigin': r\"httpUnsafeOrigin.*?'([^']+)'\",
    'adminEmail': r\"adminEmail.*?'([^']+)'\",
}
for name, pattern in patterns.items():
    m = re.search(pattern, content)
    if m:
        print(f'{name}: {m.group(0)[:80]}')
" 2>/dev/null

# Check registration status (unauthenticated)
curl -s "${CP_URL}/api/config" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
reg = d.get('restrictRegistration', False)
print(f'Open registration: {not reg}')
print(f'Admin email: {d.get(\"adminEmail\",\"\")}')
" 2>/dev/null

# Storage usage (public stats endpoint)
curl -s "${CP_URL}/api/usage" 2>/dev/null | python3 -c "
import json,sys
try:
    d=json.load(sys.stdin)
    print(f'Registered users: {d.get(\"users\")}')
    print(f'Documents: {d.get(\"pads\")}')
    print(f'Files: {d.get(\"files\")}')
except: pass
" 2>/dev/null

CryptPad Security Hardening

CryptPad Security Hardening Checklist:
Security TestMethodRisk
adminKeys misconfiguration and admin panel accessVerify config.adminKeys contents — empty array locks everyone out; wrong key blocks legitimate admin; test /admin/ panel accessibility and functionality with own keysHigh
MongoDB unauthenticated access — session token extractionmongo cryptpad db.sessions.find() — active session tokens for all users; use tokens to authenticate as any user without passwordCritical
Open registration detectionGET /api/config — restrictRegistration: false reveals open registration; unauthorized account creation enables access to shared documents and storage consumptionMedium
mongoUri credential extraction from config.jsRead config.js mongoUri — MongoDB connection string with username and password; full database accessHigh
Blob storage mass enumerationGET /blob/{prefix}/{hash} — encrypted document blobs accessible by hash; mass enumeration possible to map document existence without decrypting contentLow

Automate CryptPad Security Testing

Ironimo tests CryptPad deployments for MongoDB unauthenticated access and session token extraction, adminKeys misconfiguration detection, open registration status via /api/config, mongoUri credential extraction from config.js, blob storage unauthenticated access assessment, /api/usage statistics disclosure, httpUnsafeOrigin misconfiguration detection, Docker CPAD_ environment variable exposure, block storage path traversal testing, and admin panel accessibility verification.

Start free scan