Breachwire.riscent

Breach report

Ivanti Connect Secure: two bugs chained into unauthenticated RCE

Web Application BreachesCritical (chained unauthenticated RCE)CVE-2023-46805 + CVE-2024-218872024-01
The bottom lineAttackers chained an authentication bypass (CVE-2023-46805) with a command-injection flaw (CVE-2024-21887) in Ivanti Connect Secure and Policy Secure gateways to achieve unauthenticated remote code execution, deploying webshells and stealing credentials.
Category
Web Application Breaches
Type
CVE · Chained zero-day, exploited in the wild
Date
2024-01
Severity
Critical (chained unauthenticated RCE)
OWASP
Web A07 Authentication Failures + A05 Injection
CWE / CVE
CWE-287 / CWE-77 CVE-2023-46805 + CVE-2024-21887

What happened

Ivanti Connect Secure (formerly Pulse Connect Secure) and Policy Secure are widely deployed VPN and network-access gateways. On January 10, 2024, Ivanti disclosed two vulnerabilities in their web components: CVE-2023-46805, an authentication bypass, and CVE-2024-21887, a command-injection flaw. Security firm Volexity had already observed the pair being exploited together as zero-days in December 2023. Chained, they let an unauthenticated attacker reach an administrative function and then inject operating-system commands — full unauthenticated remote code execution. Observed post-exploitation activity included webshell deployment, backdooring of legitimate files, credential and configuration theft, and lateral movement. Affected versions were 9.x and 22.x.

Neither bug alone was game-over; together they collapsed the entire access-control boundary of an internet-facing security gateway.

Root cause

Two distinct weaknesses composed. CVE-2023-46805 (CWE-287, improper authentication) let requests bypass control checks and reach restricted resources without valid credentials. CVE-2024-21887 (CWE-77, command injection) allowed crafted requests to execute arbitrary commands through an admin-facing endpoint. The auth bypass unlocked the injection, turning an "authenticated-only" command primitive into an unauthenticated one.

How it would have been caught

Authorization tests that assert every privileged endpoint rejects an unauthenticated request would have flagged the bypass; taint-tracking static analysis (CodeQL, Semgrep) flags untrusted input flowing into a shell/exec call for the injection. A reproduction sends the unauthenticated request through the bypass and confirms an injected command actually runs on the appliance.

How to prevent it

  • Enforce authorization at every endpoint and test it negatively — an unauthenticated request to a privileged route must fail closed.
  • Never pass untrusted input to a shell; use parameterized process APIs and strict allow-lists for any command arguments.
  • Treat chained exploitation as the norm for edge devices: patch on disclosure and hunt for webshells, since zero-day activity often precedes the advisory.

The Breachwire test (red → green)

Send the crafted unauthenticated request and confirm it both bypasses auth and executes an injected command — the RED control. Fix authorization to reject the unauthenticated request and replace the shell call with a parameterized API, then confirm the request is denied and the injection payload is treated as inert data.