CVE-2026-44901: Verified Reproduction
CVE-2026-44901: Wazuh cluster DAPI deserialization of untrusted data — RCE via sort casting builtin resolution getattr builtins, 'exec' in result merging
CVE-2026-44901 is verified against wazuh/wazuh · github. Affected versions: wazuh-manager >= 4.0.0, < 4.14.6 (all cluster-mode deployments). Vulnerability class: RCE. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00325.
What Is CVE-2026-44901?
CVE-2026-44901 is a high-severity RCE vulnerability affecting wazuh/wazuh wazuh-manager >= 4.0.0, < 4.14.6 (all cluster-mode deployments). Pruva has independently reproduced it and publishes a verified, runnable proof-of-concept (reproduction REPRO-2026-00325).
CVE-2026-44901 Severity
CVE-2026-44901 is rated high severity.
High — serious impact or readily exploitable. Prioritize remediation.
Affected wazuh/wazuh Versions
wazuh/wazuh · github versions wazuh-manager >= 4.0.0, < 4.14.6 (all cluster-mode deployments) are affected.
How to Reproduce CVE-2026-44901
pruva-verify REPRO-2026-00325 curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00325/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-44901
- reached the target end-to-end
- full exploit chain demonstrated
- on the real production code path
- high confidence
- the upstream fix blocks the same trigger
Fernet-framed malicious Wazuh worker dapi_res JSON with sort_casting=["exec"] and payload in affected_items[*].x
- TCP worker peer
- MasterHandler.execute(dapi_fwd)
- dapi.py json.loads(object_hook=as_wazuh_object)
- reduce(or_)
- results.py merge/getattr(builtins,'exec')
reproduction_steps.sh How the agent worked
Root Cause and Exploit Chain for CVE-2026-44901
CVE-2026-44901 is a Wazuh cluster Distributed API (DAPI) deserialization vulnerability in which a malicious or compromised worker node can return a crafted serialized AffectedItemsWazuhResult to a master node. In vulnerable code, AffectedItemsWazuhResult.decode_json() accepts attacker-controlled sort_casting values and merge() resolves those values with getattr(builtins, type_). A worker response containing sort_casting=["exec"] therefore makes the master call Python exec() on attacker-controlled item data while merging results from multiple nodes.
- Affected package/component: Wazuh manager cluster framework, specifically
framework/wazuh/core/results.pyas reached throughframework/wazuh/core/cluster/dapi/dapi.pyand the cluster TCP channel handled bywazuh.core.cluster.master.MasterHandler/wazuh.core.cluster.common.Handler. - Affected versions: Wazuh manager cluster deployments before the fix commit
b29849f8abb08d78f257e6106b6111a8a1b0e621(reported as fixed in 4.14.6 and later). The reproduced vulnerable revision is the fixed commit parent:24609e140155d7fd2bddd4ebb045dbde5bea320f. - Risk level and consequences: High. A malicious/compromised worker node, or an attacker with the shared cluster key able to act as a worker on the cluster channel, can cause code/command execution in the master-side Wazuh process when a distributed API response is merged.
Impact Parity
- Disclosed/claimed maximum impact: Code execution on the Wazuh cluster master via the TCP/1516 Fernet-encrypted cluster channel and DAPI result merging.
- Reproduced impact from this run: Code execution/command execution on the master-side Wazuh process. The payload executed via
exec()and wrote unique marker files during both vulnerable attempts. - Parity:
full - Not demonstrated: No additional privilege escalation beyond the privileges of the reproduced master-side process was claimed or required for this proof. The proof uses a minimally configured product cluster runtime rather than full Dockerized Wazuh service containers because Docker is unavailable in this environment, but it exercises the original Wazuh cluster TCP/Fernet framing,
MasterHandler,DistributedAPI.forward_request,json.loads(..., object_hook=as_wazuh_object), andresults.pymerge sink.
Root Cause
The root cause is unsafe deserialization and later use of trusted-as-code type names from a worker-provided JSON result object.
In the vulnerable commit 24609e140155d7fd2bddd4ebb045dbde5bea320f:
AffectedItemsWazuhResult.decode_json()inframework/wazuh/core/results.pystoresobj['sort_casting']directly into the result object.- During DAPI result merging,
AffectedItemsWazuhResult.__or__()callsmerge(..., types=self.sort_casting). merge()constructs casters usinggetattr(builtins, type_)without an allowlist._goes_before_than()applies each caster to sort values. If the worker suppliedsort_casting=["exec"], the caster becomes Python built-inexec, and the corresponding item value is executed as Python source.
The product path that reaches this is:
- Master forwards a distributed request to the worker through
MasterHandler.execute(command=b'dapi_fwd', ...). - The worker response is delivered through the original Wazuh cluster string protocol (
new_str,str_upd,dapi_res) over the Fernet-encrypted cluster TCP channel. dapi.pyparses the worker response withjson.loads(..., object_hook=c_common.as_wazuh_object).as_wazuh_object()callsAffectedItemsWazuhResult.decode_json().- With more than one node response,
dapi.pymerges results usingreduce(or_, response), triggeringresults.pysorting/casting.
The fix commit is:
b29849f8abb08d78f257e6106b6111a8a1b0e621
That commit adds validation in decode_json() and an explicit ALLOWED_CASTERS map in merge(), allowing only int, float, str, and bool. The same malicious sort_casting=["exec"] response is rejected with WazuhInternalError: Invalid sort_casting type 'exec'. Allowed types: bool, float, int, str.
Reproduction Steps
- Run
bundle/repro/reproduction_steps.sh. - The script:
- Reuses the prepared Wazuh repository at
/pruva/project-cache/repowhen available. - Resolves the fixed commit and vulnerable parent.
- Verifies the vulnerable revision still contains
getattr(builtins, type_)and the fixed revision contains the newsort_castingallowlist. - Creates worktrees for
24609e140155d7fd2bddd4ebb045dbde5bea320fandb29849f8abb08d78f257e6106b6111a8a1b0e621. - Starts a minimally configured real Wazuh master cluster TCP listener using
wazuh.core.cluster.master.MasterHandlerandwazuh.core.cluster.common.Handlerwith Fernet enabled. It binds to127.0.0.1:1516when available. - Connects a malicious worker peer over the original Wazuh cluster frame format, completes the encrypted
hellohandshake, receives the masterb'dapi'forwarded request, and returns the crafted JSON through the originalnew_str/str_upd/dapi_ressequence. - Runs two vulnerable attempts and two fixed attempts.
- Reuses the prepared Wazuh repository at
- Expected evidence:
- Vulnerable attempts produce
repro/markers/product_marker_vuln_1.txtandrepro/markers/product_marker_vuln_2.txt, each containing the unique marker value selected for that process. - Fixed attempts reach the same DAPI/object-hook path but reject
sort_casting='exec'and do not create marker files. bundle/repro/validation_verdict.jsonreportsclaim_outcome=confirmed,validated_surface=network_protocol,evidence_scope=production_path, andobserved_impact_class=code_execution.
- Vulnerable attempts produce
Evidence
Primary runtime artifacts are listed and digest-bound in bundle/repro/runtime_manifest.json.
Key files from the final successful run:
bundle/logs/product_patch_check.log— commit identity and patch absence/presence check.bundle/logs/product_vuln_1.logandbundle/logs/product_vuln_2.log— vulnerable product-path attempts.bundle/logs/product_fixed_1.logandbundle/logs/product_fixed_2.log— fixed negative-control attempts.bundle/repro/observations/product_vuln_1.jsonandbundle/repro/observations/product_vuln_2.json— structured observations showingfernet_enabled=true,master_listened=true,dapi_forward_request_received_by_worker=true,worker_response_delivered_via_send_string=true,dapi_json_object_hook_path_reached=true, andmarker_present=true.bundle/repro/observations/product_fixed_1.jsonandbundle/repro/observations/product_fixed_2.json— structured observations showing the same network/DAPI path was reached butsort_casting_rejected=trueandmarker_present=false.bundle/repro/markers/product_marker_vuln_1.txtandbundle/repro/markers/product_marker_vuln_2.txt— command-execution markers written by the vulnerable master-side process.bundle/repro/evil_worker_response.json— the attacker-controlled worker JSON response containingsort_casting=["exec"]and the payload inaffected_items[*].x.
Representative vulnerable evidence from the product logs:
MASTER_LISTENING original_wazuh_cluster_tcp=127.0.0.1:1516 ... fernet_key_len=32WORKER_HELLO_ACCEPTED response=b'Client worker01 added'WORKER_GOT_DAPI_REQUEST request_id=... json_len=550 ...WORKER_SEND_STRING_UPDATED malicious JSON stored in master MasterHandler.in_strWORKER_DAPI_RES_ACKNOWLEDGED master accepted dapi_res and released pending DistributedAPI requestMASTER_DAPI_RESULT type=AffectedItemsWazuhResult ... '_sort_casting': ['exec'] ...MARKER_CHECK ... present=True content='CVE-2026-44901-vuln-...'
Representative fixed evidence:
MASTER_DAPI_RESULT type=WazuhInternalError ... "Invalid sort_casting type 'exec'. Allowed types: bool, float, int, str"MARKER_CHECK ... present=False content=None
Environment details captured:
- Repository URL:
https://github.com/wazuh/wazuh.git - Vulnerable commit:
24609e140155d7fd2bddd4ebb045dbde5bea320f - Fixed commit:
b29849f8abb08d78f257e6106b6111a8a1b0e621 - Entrypoint: Wazuh cluster TCP peer (
entrypoint_kind="tcp_peer") - Runtime stack: Wazuh
MasterHandler, Wazuh Fernet frameHandler, WazuhDistributedAPI.forward_request, WazuhAffectedItemsWazuhResult.merge, Python 3
Recommendations / Next Steps
- Use the fixed implementation from
b29849f8abb08d78f257e6106b6111a8a1b0e621or upgrade to Wazuh 4.14.6 or later. - Keep
sort_castingvalidation both at deserialization time and at use time. Only safe, explicit caster names should be accepted. - Avoid resolving attacker-provided strings into arbitrary built-ins or callables.
- Add regression tests that replay serialized worker
AffectedItemsWazuhResultresponses with invalid caster names such asexec,eval,open, and non-string/list values. - Consider hardening the DAPI worker-response trust boundary: even authenticated cluster workers should not be able to deserialize data structures that influence executable behavior on the master.
Additional Notes
- The final
bundle/repro/reproduction_steps.shwas executed twice consecutively and succeeded both times. - Each script run performs two vulnerable attempts and two fixed attempts with fresh per-process marker values.
- Docker was not available in this environment, so the proof uses a minimally configured local Wazuh cluster runtime from the real source tree rather than Wazuh container images. It does not reimplement the vulnerable sink or the cluster frame protocol; it imports and executes the real Wazuh modules for the master TCP listener, Fernet framing, DAPI forwarding, JSON object hook, and result merging.
- The reproduction is self-contained: it creates runtime helper code and payload files at execution time, installs Python dependencies into
bundle/repro/venvif needed, and writes all proof diagnostics underbundle/logs/andbundle/repro/.
CVE-2026-44901 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
python3 --version; ls /usr/bin/python*; pip3 --version 2>/dev/null; df -h /workspace | tail -1; nproc; free -m | head -2Python 3.14.4 /usr/bin/python /usr/bin/python3 /usr/bin/python3-config /usr/bin/python3.14 /usr/bin/python3.14-config pip 25.1.1 from /usr/lib/python3/dist-packages/pip (python 3.14) tmpfs 4.0G 40K 4.0G 1% /workspace
cd /pruva/project-cache/repo-mirrors/wazuh.git && git tag -l 'v4.14.*' | sort -V && git log --oneline -1v4.14.0 v4.14.1 v4.14.2 v4.14.3 v4.14.4 v4.14.5 v4.14.6 v4.14.7
Artifacts and Evidence for CVE-2026-44901
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix CVE-2026-44901
FAQ: CVE-2026-44901
Is CVE-2026-44901 exploitable?
How severe is CVE-2026-44901?
What type of vulnerability is CVE-2026-44901?
Which versions of wazuh/wazuh are affected by CVE-2026-44901?
How can I reproduce CVE-2026-44901?
Is the CVE-2026-44901 reproduction verified?
References for CVE-2026-44901
Authoritative sources for CVE-2026-44901 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.