Cachet Security Testing: Default Credentials, API Key, Database, and APP_KEY Session Forgery

Cachet is a widely deployed self-hosted status page system used by organizations to communicate service availability to customers and internal teams — it knows about every monitored service and component in your infrastructure. Key assessment areas: APP_KEY is the Laravel application encryption key that signs session cookies; the API key (X-Cachet-Token header) enables full incident and component management; the public API may expose internal infrastructure component names and status history without authentication; the database stores all subscriber email addresses and internal incident details; and Cachet's known CVE-2021-39172 template injection vulnerability may exist on unpatched deployments. This guide covers systematic Cachet security assessment.

Table of Contents

  1. Default Credentials and Public API Infrastructure Enumeration
  2. API Key Authentication and Incident Management
  3. APP_KEY and Database Subscriber/Incident Extraction
  4. Cachet Security Hardening

Default Credentials and Public API Infrastructure Enumeration

# Cachet — default credentials and public API infrastructure enumeration
CACHET_URL="https://status.example.com"

# Cachet API is partially public — components and incidents visible without auth
# This reveals internal infrastructure topology

# Enumerate all components (internal services) WITHOUT authentication
curl -s "${CACHET_URL}/api/v1/components" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
data = d.get('data',[])
meta = d.get('meta',{})
print(f'Components: {meta.get(\"pagination\",{}).get(\"total\",len(data))} total')
for c in data[:20]:
    print(f'  [{c.get(\"id\")}] {c.get(\"name\")} status={c.get(\"status\")} ({c.get(\"status_name\")})')
    print(f'    description={c.get(\"description\",\"\")[:80]}')
    print(f'    enabled={c.get(\"enabled\")} link={c.get(\"link\",\"\")}')
" 2>/dev/null
# Reveals internal service names, descriptions, and links — infrastructure map

# Enumerate all incidents (internal outage history) WITHOUT authentication
curl -s "${CACHET_URL}/api/v1/incidents?sort=id&order=desc&per_page=50" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
data = d.get('data',[])
print(f'Incidents: {len(data)}')
for i in data[:10]:
    print(f'  [{i.get(\"id\")}] {i.get(\"name\")} status={i.get(\"status\")} ({i.get(\"human_status\")})')
    print(f'    message={str(i.get(\"message\",\"\"))[:100]}')
    print(f'    occurred_at={i.get(\"occurred_at\")} created_at={i.get(\"created_at\")}')
" 2>/dev/null
# Incident messages often contain internal technical details, root cause analysis

# Check for CVE-2021-39172 — Server-Side Template Injection in Cachet 2.3.x/2.4.x
# The 'name' field in components/incidents was vulnerable to SSTI
curl -s "${CACHET_URL}/api/v1/ping" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'Cachet version: {d.get(\"data\",\"unknown\")}')
" 2>/dev/null

API Key Authentication and Incident Management

# Cachet API key authentication and incident/component management
CACHET_URL="https://status.example.com"

# Cachet API key is in database (cachet_settings table) or .env file
# API key is passed as X-Cachet-Token header

API_KEY="your-cachet-api-key"

# Test API key authentication
curl -s "${CACHET_URL}/api/v1/components" \
  -H "X-Cachet-Token: ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
# If authenticated, may see additional private components
print(f'Authenticated components: {len(d.get(\"data\",[]))}')
" 2>/dev/null

# Get all subscribers (email addresses!)
curl -s "${CACHET_URL}/api/v1/subscribers?per_page=100" \
  -H "X-Cachet-Token: ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
data = d.get('data',[])
meta = d.get('meta',{})
print(f'Subscribers: {meta.get(\"pagination\",{}).get(\"total\",len(data))} total')
for s in data[:20]:
    print(f'  {s.get(\"email\")} verified={s.get(\"verified\")} created_at={str(s.get(\"created_at\",\"\"))[:10]}')
" 2>/dev/null
# Subscriber emails are the customer list — valuable PII

# Create fake incident (demonstrates write access with API key)
# curl -s -X POST "${CACHET_URL}/api/v1/incidents" \
#   -H "X-Cachet-Token: ${API_KEY}" \
#   -H "Content-Type: application/json" \
#   -d '{"name":"Service Degradation","message":"Investigating issue","status":1,"visible":1}'

# Get component groups
curl -s "${CACHET_URL}/api/v1/components/groups" \
  -H "X-Cachet-Token: ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
data = d.get('data',[])
print(f'Component groups: {len(data)}')
for g in data:
    print(f'  {g.get(\"name\")} collapsed={g.get(\"collapsed\")}')
" 2>/dev/null

APP_KEY and Database Subscriber/Incident Extraction

# Cachet APP_KEY and database credential extraction

# .env file — Cachet/Laravel configuration
cat /var/www/html/.env /app/.env 2>/dev/null | \
  grep -E "APP_KEY|DB_|MAIL_|CACHET_|APP_ENV|APP_URL" | head -20
# APP_KEY — Laravel application encryption key (base64 encoded)
# Cracking APP_KEY allows forging Laravel session cookies for admin access
# DB_HOST, DB_USERNAME, DB_PASSWORD, DB_DATABASE
# MAIL_HOST, MAIL_USERNAME, MAIL_PASSWORD — email configuration

# Docker inspection
docker inspect cachet 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 ['APP_KEY','DB_','MAIL_','CACHE_','APP_ENV']):
            print(e)
" 2>/dev/null

# MySQL/PostgreSQL — all Cachet data
DB_URL="mysql://cachet:PASSWORD@localhost/cachet"
mysql -h localhost -u cachet -pPASSWORD cachet 2>/dev/null << 'EOF'
-- API key from settings (alternative to .env)
SELECT `name`, `value` FROM `cachet_settings`
WHERE `name` IN ('app_key','api_key','cachet_token')
LIMIT 5;

-- All subscriber emails
SELECT email, verify_code, verified, created_at
FROM cachet_subscribers
ORDER BY created_at DESC
LIMIT 30;

-- All incidents with internal messages
SELECT id, name, message, status, visible, occurred_at
FROM cachet_incidents
ORDER BY created_at DESC
LIMIT 20;

-- Admin users and hashed passwords
SELECT id, username, email, password, api_key, remember_token
FROM cachet_users
ORDER BY id ASC
LIMIT 10;
EOF
-- api_key: plaintext API key for each admin user
-- password: bcrypt hashed passwords for offline cracking

Cachet Security Hardening

Cachet Security Hardening Checklist:
Security TestMethodRisk
Public API unauthenticated infrastructure enumerationGET /api/v1/components and /api/v1/incidents — no authentication required; reveals all monitored service names, descriptions, incident history with internal details; complete infrastructure component map for reconnaissanceMedium
APP_KEY extraction and Laravel session forgeryRead .env APP_KEY — forge Laravel session cookies for any Cachet user; full admin panel access without credentials; API key extraction, subscriber enumeration, incident manipulationHigh
Database cachet_users API key extractionSELECT api_key FROM cachet_users — plaintext API keys for all admin users; full incident and component management capability; subscriber email list access via authenticated APIHigh
Subscriber email list extractionGET /api/v1/subscribers with API key — complete customer subscriber email list; GDPR-regulated personal data; targeted phishing list; customer count intelligence disclosureHigh
CVE-2021-39172 Server-Side Template InjectionInject Blade template syntax in component/incident name fields — authenticated SSTI in Cachet 2.3.x/2.4.x; Remote Code Execution on unpatched deployments; affects name, message, and notification fieldsCritical (if unpatched)

Automate Cachet Security Testing

Ironimo tests Cachet deployments for APP_KEY extraction and Laravel session cookie forgery, database cachet_users API key extraction, subscriber email list enumeration, CVE-2021-39172 SSTI assessment on unpatched versions, public API unauthenticated infrastructure component enumeration, incident message internal detail disclosure, Docker APP_KEY/DB_PASSWORD exposure, admin password hash extraction for offline cracking, bcrypt strength assessment, and API key privilege level testing.

Start free scan