Wazuh occupies a privileged position in most environments: it sees everything, talks to everything, and its agents run with root or SYSTEM privileges on every managed endpoint. That is exactly why the Zero Day Initiative's disclosure of ZDI-26-528 / CVE-2026-28220 — a deserialization of untrusted data vulnerability in the Wazuh Cluster Distributed API (DAPI) protocol carrying a CVSS score of 9.9 — demands immediate attention from every team running a multi-node Wazuh deployment. A flaw that allows arbitrary code execution on the manager from a worker node isn't just a bug in a monitoring tool; it's a potential path to full control of your security telemetry, your agent fleet, and every endpoint your EDR/XDR stack touches.
This post breaks down what the vulnerability is, the realistic attack prerequisites, how to hunt for exploitation attempts today, and what to do about it.
Technical Analysis
What is affected
The vulnerability exists in the Wazuh Cluster DAPI (Distributed API) protocol, the internal communication layer used between Wazuh master and worker nodes in clustered deployments. The DAPI forwards requests from workers to the master (or other nodes) for distributed execution — configuration reads, agent operations, cluster coordination. The flaw is a classic deserialization of untrusted data weakness: attacker-controlled data crossing the cluster trust boundary is deserialized and processed by a privileged component without sufficient validation, yielding arbitrary code execution.
Key scoping notes:
- CVE: CVE-2026-28220 (ZDI advisory ZDI-26-528)
- CVSS: 9.9 (Critical)
- Affected deployments: Wazuh cluster environments — master and worker node architectures. Standalone single-server installs that do not run
wazuh-clusterdreduce the exposed surface, but any deployment with clustering enabled should be treated as vulnerable until patched. - Prerequisite: Per the ZDI advisory, the attacker must first obtain the ability to execute low-privileged code on a worker node. This is not a remote unauthenticated bug over the internet — it is a pivot amplification primitive. Once an attacker lands on any single worker (via a compromised agent enrollment, a weak admin credential, an exposed Wazuh API, or a supply-chain path), they can escalate laterally within the cluster and achieve code execution on the master node, which is the crown jewel: API keys, agent auth keys, and command-and-control over every enrolled endpoint.
Why CVSS 9.9 makes sense
The score reflects a changed scope: exploitation compromises a component beyond the vulnerable component's security authority. A low-privileged foothold on a worker becomes code execution in the context of the cluster's most trusted process. Wazuh services run as the wazuh user but orchestrate root-level agent operations fleet-wide. Practically, full compromise of a Wazuh master means:
- Push of malicious active response commands or custom scripts to every agent in the fleet
- Extraction of
client.keysand agent authentication material - Blindness: tampering with or deleting the very alerts that would report the intrusion
- Access to the Wazuh indexer/dashboard stack and any integrations (Slack, TheHive, SOAR webhooks) holding additional credentials
Exploitation status
At time of writing, this is a ZDI-coordinated disclosure — there is no confirmed in-the-wild exploitation and no public weaponized PoC, and the CVE does not yet appear in the CISA KEV catalog. That will not last. Wazuh is open source, widely deployed (tens of thousands of clusters), and deserialization primitives in internal cluster protocols are historically fast to be reverse-engineered once patches ship and diffs are published. Treat the patch window as days, not weeks.
The realistic attack chain
- Attacker gains low-privileged execution on a worker node (credential theft, exposed API port 55000, phished admin, vulnerable third-party service on the same host).
- From the worker's network position, attacker speaks the cluster protocol to the master (default cluster communication over TCP 1516).
- Malicious serialized DAPI payload is submitted through a legitimate-looking cluster request.
- The master deserializes the payload in a privileged code path → arbitrary code execution as the Wazuh service context on the master.
- Attacker leverages master control for fleet-wide persistence via active response, agent upgrades, or configuration pushes.
Detection & Response
This is a technical threat, and the most reliable telemetry comes from three places: (1) cluster-port network traffic from unexpected sources, (2) child processes spawned by Wazuh daemons — post-deserialization code execution almost always manifests as wazuh-clusterd, wazuh-apid, or the Wazuh Python runtime spawning shells or downloaders, and (3) cluster log anomalies in /var/ossec/logs/cluster.log.
Sigma Rules
---
title: Wazuh Cluster Daemon Spawning Shell or Downloader
id: 3f8c1a92-7b4e-4d21-9c56-8a2e1f5b9d04
status: experimental
description: Detects Wazuh cluster or API daemons spawning shells, interpreters, or download tools, consistent with post-exploitation of CVE-2026-28220 DAPI deserialization.
references:
- https://www.zerodayinitiative.com/advisories/ZDI-26-528/
- https://attack.mitre.org/techniques/T1059/
author: Security Arsenal
date: 2026/04/06
tags:
- attack.execution
- attack.t1059
logsource:
category: process_creation
product: linux
detection:
selection_parent:
ParentCommandLine|contains:
- 'wazuh-clusterd'
- 'wazuh-apid'
- 'wazuh-modulesd'
- '/var/ossec/framework/python/bin/python3'
selection_child:
Image|endswith:
- '/sh'
- '/bash'
- '/dash'
- '/zsh'
- '/curl'
- '/wget'
- '/nc'
- '/ncat'
- '/python'
- '/python3'
- '/perl'
condition: selection_parent and selection_child
falsepositives:
- Rare; legitimate Wazuh integrations and active response scripts can invoke shells - tune by approved active-response script paths
level: high
---
title: Unexpected Host Connecting to Wazuh Cluster Port 1516
id: 91d4e2b7-6c3a-4f18-b872-4e9a7d3c1f50
status: experimental
description: Detects network connections to the Wazuh cluster communication port from hosts that are not known cluster peers, indicating possible DAPI exploitation attempts.
references:
- https://www.zerodayinitiative.com/advisories/ZDI-26-528/
- https://attack.mitre.org/techniques/T1210/
author: Security Arsenal
date: 2026/04/06
tags:
- attack.exploitation
- attack.t1210
- attack.lateral_movement
logsource:
category: network_connection
product: linux
detection:
selection:
DestinationPort: 1516
Image|contains: 'wazuh-clusterd'
filter_known_cluster_peers:
SourceIp:
- '10.0.0.0/8' # REPLACE with your actual worker node IP ranges
condition: selection and not filter_known_cluster_peers
falsepositives:
- Newly provisioned worker nodes not yet added to the allowlist
- Port scans from internal vulnerability scanners
level: medium
Tune the second rule's SourceIp filter to your actual cluster inventory — in a properly segmented environment, only worker nodes should ever initiate to TCP 1516 on the master. Any other source is investigation-worthy by definition.
KQL — Microsoft Sentinel (via Syslog/CEF ingestion)
Wazuh ships its own logs to /var/ossec/logs/; if you forward Wazuh server Syslog into Sentinel, this hunts both child-process anomalies and cluster-port connections from non-peer sources.
// Hunt 1: Wazuh daemons spawning suspicious child processes (Linux auditd/Sysmon-for-Linux telemetry)
let suspicious_children = dynamic(["/bin/sh","/bin/bash","/bin/dash","/usr/bin/curl","/usr/bin/wget","/bin/nc","/usr/bin/ncat","/usr/bin/perl"]);
DeviceProcessEvents
| where TimeGenerated > ago(7d)
| where InitiatingProcessCommandLine has_any ("wazuh-clusterd","wazuh-apid","wazuh-modulesd","/var/ossec/framework/python")
| where FileName has_any ("sh","bash","curl","wget","nc","ncat","perl","python")
or ProcessCommandLine has_any ("base64","/dev/tcp/","curl ","wget ","chmod +x")
| project TimeGenerated, DeviceName, InitiatingProcessCommandLine, FileName, ProcessCommandLine, AccountName
| order by TimeGenerated desc;
// Hunt 2: Cluster port 1516 connections from unexpected sources (Syslog/CEF firewall or netflow)
CommonSecurityLog
| where TimeGenerated > ago(7d)
| where DestinationPort == 1516
| summarize ConnectionCount = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by SourceIP, DestinationIP, DeviceAction
| order by ConnectionCount desc
Velociraptor VQL
Deploy this as a hunt across your Wazuh master and worker nodes to identify suspicious children of the cluster daemon and unexpected listeners/peers on the cluster port.
-- Wazuh cluster post-exploitation hunt: child processes of Wazuh daemons and cluster-port state
SELECT Pid, Ppid, Name, Exe, CommandLine, Username, CreateTime
FROM pslist()
WHERE CommandLine =~ '(wazuh-clusterd|wazuh-apid|wazuh-modulesd|/var/ossec/framework/python)'
OR Exe =~ '(bin/sh|bin/bash|bin/dash|usr/bin/(curl|wget|nc|ncat|perl))'
SELECT Pid, Name, LocalAddress, LocalPort, RemoteAddress, RemotePort, Status
FROM netstat()
WHERE LocalPort = 1516 OR RemotePort = 1516
Correlate the two result sets: any wazuh-clusterd process holding 1516 connections to/from IPs outside your cluster inventory, or any shell/downloader process whose parent PID maps to a Wazuh daemon, is a strong exploitation signal.
Remediation / Verification Script
Run this on every Wazuh manager and worker node to inventory your version, lock down the cluster port to known peers, and baseline the cluster logs for review.
#!/bin/bash
# CVE-2026-28220 Wazuh cluster hardening & verification script
# Run on master and all worker nodes. Requires root.
echo "=== [1] Wazuh version check ==="
WAZUH_VER=$(/var/ossec/bin/wazuh-control info 2>/dev/null | grep -i version || cat /var/ossec/VERSION.json 2>/dev/null)
echo "$WAZUH_VER"
echo "ACTION REQUIRED: Confirm this build includes the CVE-2026-28220 fix per Wazuh security advisory."
echo "=== [2] Confirm clustering is enabled (exposure check) ==="
grep -A5 '<cluster>' /var/ossec/etc/ossec.conf | grep -E 'disabled|node_type|node_name'
echo "=== [3] Current listeners on cluster port 1516 ==="
ss -tlnp | grep ':1516' || echo "No listener on 1516 - clustering may be disabled (reduced exposure)."
echo "=== [4] Lock down TCP 1516 to known cluster peers only ==="
# EDIT: replace with your actual worker/master IPs
MASTER_IP="10.10.10.10"
WORKER_IPS=("10.10.10.11" "10.10.10.12")
for IP in "${WORKER_IPS[@]}"; do
iptables -C INPUT -p tcp -s "$IP" --dport 1516 -j ACCEPT 2>/dev/null || iptables -I INPUT -p tcp -s "$IP" --dport 1516 -j ACCEPT
done
iptables -C INPUT -p tcp --dport 1516 -j DROP 2>/dev/null || iptables -A INPUT -p tcp --dport 1516 -j DROP
echo "Applied: 1516 restricted to ${WORKER_IPS[*]} (default-deny for all others)."
echo "=== [5] Cluster log anomalies in last 24h ==="
grep -iE 'error|exception|traceback|dapi|deserialize|pickle' /var/ossec/logs/cluster.log 2>/dev/null | tail -n 50
echo "=== [6] Suspicious children of Wazuh daemons (live) ==="
for PID in $(pgrep -f 'wazuh-clusterd|wazuh-apid|wazuh-modulesd'); do
ps --ppid "$PID" -o pid,ppid,user,comm,args 2>/dev/null
done
echo "=== Done. Review sections 5-6 output. Any traceback/deserialization errors or shell children = escalate to IR. ==="
Remediation
- Patch immediately. Apply the Wazuh release that resolves CVE-2026-28220 per the official vendor advisory and the ZDI coordination page at http://www.zerodayinitiative.com/advisories/ZDI-26-528/. Check Wazuh's security advisories page (wazuh.com and github.com/wazuh/wazuh/security/advisories) for the fixed version for your release train. Patch the master first, then workers — the master is the deserialization target.
- Segment the cluster port. TCP 1516 (cluster communications) and 55000 (Wazuh server API) must be reachable only from authenticated cluster peers and approved admin networks. If your cluster nodes share a flat network with general workloads, that is the finding to fix this week — the CVSS 9.9 score assumes exactly that adjacency.
- Reduce the foothold surface. The attack requires low-privileged code execution on a worker first. Audit worker nodes for unnecessary services, stale credentials, exposed API bindings (the API should bind to a management interface, not 0.0.0.0), and enforce MFA on the Wazuh dashboard.
- Rotate credentials if you suspect exposure. If forensic review shows cluster-port anomalies pre-patch, rotate the cluster key in
ossec.conf, the API credentials,client.keysagent auth material, and any credentials stored in integrations — assume anything the master could reach is compromised. - Enable and centralize cluster logging. Ship
/var/ossec/logs/cluster.logandossec.logoff-box in real time. Attackers who own the master will try to blind you locally; your only trustworthy copy is the one they can't touch. - Monitor for the patch-diff PoC window. Open-source projects get diffed within hours of a security release. Subscribe to Wazuh's security feed and watch for public PoC publication — historically, N-day exploitation of SIEM/management-plane bugs follows within days.
The Bottom Line
CVE-2026-28220 is a reminder that security tooling is itself high-value attack surface. Your Wazuh master holds the keys to every agent in your fleet — which makes a cluster-internal deserialization flaw with a 9.9 score a treat-this-weekend event, not a next-quarter patch cycle item. Patch the master, segment port 1516, hunt for daemon child processes, and verify your logs are flowing somewhere an attacker can't reach.
Related Resources
Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.