This is a stolen maintenance badge for the server room, not a rock through the front window
CVE-2026-30893 is a path traversal in Wazuh cluster synchronization. In affected wazuh-manager versions >=4.4.0 and <4.14.4, the decompress_files() routine trusts attacker-controlled file paths from a cluster sync archive and joins them into the extraction path without containment checks. A malicious cluster peer can therefore write files outside the intended directory on other cluster nodes, then turn that into code execution by overwriting Python modules Wazuh loads.
The vendor's *impact* rating is understandable, but the operational severity is lower than a typical CRITICAL because the attacker does not get this from the public edge anonymously. They need authenticated cluster-peer position: internal reachability to port 1516/TCP, clustering enabled, and either control of an existing Wazuh node or possession of the shared 32-character cluster key. That is still bad for clustered deployments, especially where the manager runs as root, but it is classic post-compromise lateral movement rather than broad initial access.
4 steps from start to impact.
Obtain cluster-peer position
/var/ossec/etc/ossec.conf, or otherwise gaining authenticated access to the cluster protocol on 1516/TCP. The vendor documentation shows the cluster uses a shared 32-character key across nodes, so one node compromise can unlock trust to the others.- Wazuh deployed in cluster mode
- Network reachability to cluster port
1516/TCP - Shared cluster key or control of an existing cluster node
- Single-node Wazuh managers are out of scope
- This assumes post-initial-access or credential/secret theft
- Modern east-west firewalling should restrict who can reach
1516/TCP
Craft malicious sync archive
../../ traversal or absolute paths such as /etc/cron.d/backdoor. The published PoC uses poc_complete.py and the native Wazuh decompress_files() behavior to demonstrate the payload format and file creation.- Authenticated cluster communication accepted by target node
- Ability to send cluster sync content as a trusted peer
- Payload has to match Wazuh's cluster sync format
- If defenders monitor unexpected cluster sync behavior, this can stand out
Trigger arbitrary file write on peer node
wazuh-clusterd and related sync flows. Because the vulnerable code joins attacker-controlled paths without safe containment, the write escapes the extraction directory and lands anywhere the service account can write.- Victim node runs a vulnerable version
>=4.4.0and<4.14.4 - Cluster synchronization path reaches the vulnerable decompression flow
- Write permission still depends on the effective UID of the Wazuh service
- Non-root deployments limit the attacker to Wazuh-writable paths
/var/ossec/etc/, /var/ossec/wodles/, /tmp/, /etc/cron.d/, or SSH key locations by Wazuh processes.Escalate to Wazuh-context RCE or root
- Writable execution path such as Wazuh-loaded Python modules
- Or elevated runtime allowing writes to privileged locations
- Least-privilege service accounts reduce full-host takeover
- File integrity monitoring or EDR may catch module tampering before execution
The supporting signals.
| In-the-wild status | No verified in-the-wild exploitation found in authoritative sources reviewed. Not in CISA KEV as of this assessment, and I found no vendor-confirmed campaign reporting. |
|---|---|
| Proof-of-concept availability | Yes. The GitHub Security Advisory includes a working poc_complete.py demonstrating traversal and arbitrary file write via the real decompress_files() logic. |
| EPSS | 0.00082 from the intel you supplied, which is very low and aligns with the narrow attacker prerequisites. Public third-party mirrors place it around the low-20s percentile, but that percentile was not independently verified from FIRST directly in this review. |
| KEV status | No. No CISA KEV listing found for CVE-2026-30893; therefore no known federal exploitation deadline is attached. |
| CVSS vector reality check | Vendor vector: CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:H/A:H = network reachable but high privileges required. That privilege requirement is the whole story here: this is cluster-peer abuse, not anonymous edge RCE. |
| Affected versions | wazuh-manager versions >=4.4.0 and <4.14.4 per the GitHub advisory and NVD record. |
| Fixed versions | Vendor advisory says patched in 4.14.4. The v4.14.4 release notes mention improved cluster file synchronization path handling via safe path joins. A backport issue exists for the 4.10.4 branch, but the advisory itself names 4.14.4 as the authoritative fixed release. |
| Exposure population | This only matters on clustered Wazuh managers. Vendor docs show cluster comms on 1516/TCP, often with bind_addr 0.0.0.0, but that channel is intended for server-to-server sync; real exposure is therefore a narrower subset than all Wazuh installs. *Inference:* most enterprise risk is east-west, not internet-wide spray. |
| Disclosure timeline | GitHub advisory published 2026-04-28; NVD published 2026-04-29; NVD last modified 2026-04-30. The fixing code landed earlier in the v4.14.4 release published 2026-03-17. |
| Reporter / source | Public advisory source is the Wazuh GitHub Security Advisory, published under the wazuh/wazuh repository by vikman90. |
noisgate verdict.
The decisive downward pressure is the authenticated cluster-peer requirement: an attacker needs post-initial-access position, cluster reachability, and cluster trust before this bug matters. I kept it in HIGH because once those conditions are met, the flaw can turn one trusted Wazuh node or stolen cluster key into code execution and lateral movement across the rest of the security cluster.
Why this verdict
- Start from 9.0, then cut for attacker position: the vendor baseline assumes the technical impact is severe, and it is. But
PR:Hmeans the attacker already has a trusted cluster-peer foothold or the shared cluster key, which implies prior compromise or secret theft. - Cluster-only narrows the reachable population: this is irrelevant to single-node managers. Only Wazuh clusters with versions
4.4.0through4.14.3and active cluster synchronization are actually in scope. - Internal service reachability compounds the friction: the path runs over cluster port
1516/TCP, an east-west management plane that competent segmentation or security groups should already restrict. That is very different from an unauthenticated internet-facing login page bug. - Blast radius keeps it out of MEDIUM: once a malicious peer is trusted, the attacker can write files onto other Wazuh nodes and reach Wazuh-context RCE. In root-run or containerized deployments, that can become full host compromise and cluster-wide lateral movement.
Why not higher?
There is no verified KEV listing, no authoritative evidence of active exploitation, and EPSS is tiny. More importantly, the exploit chain assumes a prior breach stage: internal network position plus authenticated cluster trust. That is exactly the kind of compounding friction that should drag a vendor CRITICAL down operationally.
Why not lower?
This is still arbitrary file write leading to code execution on a central security platform. If one Wazuh node or the cluster key is lost, the bug gives the attacker an efficient path to spread across the rest of the cluster, which is too consequential for a MEDIUM or backlog-only label.
What to do — in priority order.
- Fence port 1516 — Restrict
1516/TCPto explicit Wazuh peer IPs or security groups only, and remove any broad east-west or internet exposure. For a HIGH verdict, deploy this compensating control within 30 days. - Disable unused clustering — If a manager is not intentionally part of an HA/distributed Wazuh cluster, disable the
<cluster>function entirely so the vulnerable path is unreachable. For a HIGH verdict, complete this within 30 days on any single-node managers carrying cluster config drift. - Run Wazuh as least privilege — Make sure the manager does not run as root unless there is a hard dependency, especially in Docker or Kubernetes deployments. This does not remove the bug, but it materially reduces the post-write blast radius; apply within 30 days.
- Rotate cluster secrets after node compromise — Treat the cluster key as a lateral-movement credential. If any Wazuh node is suspected compromised, rotate the shared cluster key and re-establish trust on clean nodes within 30 days, or immediately as part of incident response.
- Alert on Wazuh-origin file writes — Add EDR/FIM detections for Wazuh processes writing into
/var/ossec/etc/, Wazuh Python/module paths,/etc/cron.d/,/root/.ssh/, and other non-routine locations. Stand up these detections within 30 days so exploitation attempts are not silent.
- A WAF on the dashboard or API does not help; the vulnerable path is cluster synchronization over
1516/TCP, not the web interface. - MFA for dashboard/API admins is good hygiene but irrelevant to the cluster shared-secret trust model used here.
- Agent enrollment TLS hardening does not cover manager-to-manager sync. This is a cluster peer problem, not an agent registration problem.
- Version-only vulnerability scanning finds affected packages but does not tell you whether clustering is enabled or whether the node is actually reachable by a malicious peer.
Crowdsourced verification payload.
Run this on each Wazuh manager node, not from an auditor workstation. Invoke it as sudo bash ./check-cve-2026-30893.sh; it needs permission to execute /var/ossec/bin/wazuh-control and read /var/ossec/etc/ossec.conf. It returns VULNERABLE when the node is on an affected version *and* cluster mode appears enabled, PATCHED when the installed version is outside the affected range or fixed, and UNKNOWN when the version is affected but cluster exposure cannot be confirmed cleanly.
#!/usr/bin/env bash
# check-cve-2026-30893.sh
# Detect practical exposure to CVE-2026-30893 on a Wazuh manager node.
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -u
FIXED_VERSION="4.14.4"
AFFECTED_FLOOR="4.4.0"
WAZUH_CONTROL="/var/ossec/bin/wazuh-control"
OSSEC_CONF="/var/ossec/etc/ossec.conf"
OSSEC_INIT="/var/ossec/etc/ossec-init.conf"
say() { printf '%s\n' "$1"; }
normalize_version() {
# Strip leading v and any suffix like -rc1 or distro release.
echo "$1" | sed -E 's/^v//; s/[^0-9.].*$//' | awk -F. '{print $1 "." $2 "." $3}'
}
version_ge() {
# returns 0 if $1 >= $2
[ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | tail -n1)" = "$1" ]
}
version_lt() {
# returns 0 if $1 < $2
[ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" = "$1" ] && [ "$1" != "$2" ]
}
get_version() {
local raw=""
if [ -x "$WAZUH_CONTROL" ]; then
raw="$($WAZUH_CONTROL info -v 2>/dev/null | head -n1)"
if [ -n "$raw" ]; then
normalize_version "$raw"
return 0
fi
fi
if command -v rpm >/dev/null 2>&1; then
raw="$(rpm -q --qf '%{VERSION}\n' wazuh-manager 2>/dev/null | head -n1)"
if [ -n "$raw" ] && [ "$raw" != "package wazuh-manager is not installed" ]; then
normalize_version "$raw"
return 0
fi
fi
if command -v dpkg-query >/dev/null 2>&1; then
raw="$(dpkg-query -W -f='${Version}\n' wazuh-manager 2>/dev/null | head -n1)"
if [ -n "$raw" ]; then
normalize_version "$raw"
return 0
fi
fi
if [ -r "$OSSEC_INIT" ]; then
raw="$(grep -E '^VERSION=' "$OSSEC_INIT" 2>/dev/null | head -n1 | cut -d'=' -f2 | tr -d '"')"
if [ -n "$raw" ]; then
normalize_version "$raw"
return 0
fi
fi
return 1
}
cluster_enabled() {
# Best-effort XML check without external parsers.
# Returns:
# 0 = cluster appears enabled
# 1 = cluster appears disabled or absent
# 2 = cannot determine
[ -r "$OSSEC_CONF" ] || return 2
if ! grep -qi '<cluster>' "$OSSEC_CONF"; then
return 1
fi
# Extract the first cluster block, if present.
local block
block="$(awk 'BEGIN{inblk=0} /<cluster>/{inblk=1} {if(inblk) print} /<\/cluster>/{if(inblk){exit}}' "$OSSEC_CONF" 2>/dev/null)"
[ -n "$block" ] || return 2
if echo "$block" | grep -Eqi '<disabled>\s*yes\s*</disabled>'; then
return 1
fi
if echo "$block" | grep -Eqi '<disabled>\s*no\s*</disabled>'; then
return 0
fi
# If a cluster block exists and no explicit disabled flag is present,
# Wazuh docs indicate default is not disabled.
return 0
}
main() {
local ver=""
if ! ver="$(get_version)"; then
say "UNKNOWN - could not determine installed Wazuh manager version"
exit 2
fi
if ! echo "$ver" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then
say "UNKNOWN - unparsable Wazuh version: $ver"
exit 2
fi
# Outside affected range => patched/not affected.
if version_lt "$ver" "$AFFECTED_FLOOR"; then
say "PATCHED - installed version $ver is below affected range $AFFECTED_FLOOR"
exit 0
fi
if version_ge "$ver" "$FIXED_VERSION"; then
say "PATCHED - installed version $ver is at or above fixed version $FIXED_VERSION"
exit 0
fi
# Affected version range; now assess practical exposure via cluster mode.
if cluster_enabled; then
say "VULNERABLE - affected version $ver and cluster mode appears enabled"
exit 1
else
rc=$?
if [ "$rc" -eq 1 ]; then
say "UNKNOWN - affected version $ver but cluster mode appears disabled or absent"
exit 2
fi
say "UNKNOWN - affected version $ver and cluster configuration could not be determined"
exit 2
fi
}
main "$@"
If you remember one thing.
4.4.0 through 4.14.3, then immediately scope whether 1516/TCP is reachable beyond explicit peer nodes and whether any manager is running as root. For this HIGH verdict, the noisgate mitigation SLA is ≤30 days: restrict cluster access, disable unused clustering, and harden runtime privileges by then. The noisgate remediation SLA is ≤180 days: move affected managers to the vendor-fixed release 4.14.4 or later within that window; there is no current KEV or active-exploitation override pushing this into hours.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.