CISA KEV Load Balancer Pre-Auth RCE

One missing null byte lets strangers root any Kemp LoadMaster

Aug 12, 2026·8 min read·Chris Boker, Founder, CVEasy AI
A dark JSON envelope carrying a POST to /accessv2 with a mint apiuser row and a stack of g0 through g60 rust spray keys, a rust arrow feeding it into a central row of heap chunk tiles where the mint escape_quotes buffer sits next to a rust attacker-controlled neighbor chunk, a dashed rust overflow arc showing sprintf reading past the missing null terminator, a gold command line block assembling into a system() wrapper, and a dark LoadMaster appliance rack on the right with a mint shell prompt chip carrying a gold root hash emerging from the top

On June 29, 2026, watchTowr Labs published a one-request exploit for Progress Kemp LoadMaster, the load balancer that fronts DMZs, Exchange front ends, login pages, and whatever else companies keep in high availability at the perimeter. One anonymous POST to /accessv2 with a carefully shaped JSON body and the appliance returned a root shell. Telemetry from eSentire caught 792 exploit attempts from 65 unique IP addresses across 18 countries over the following 41 days, and on August 7 CISA added CVE-2026-8037 to KEV with a three-day FCEB deadline.

Where the shell drops out

CVE-2026-8037 carries a CVSS of 9.6: pre-auth, network reachable, root code execution. There is no CSRF token to steal, no session to hijack, no user to phish. The vulnerable code path is reachable the moment /accessv2 accepts an HTTP request, which it does on any appliance where the API is enabled. Progress lists 100,000-plus Kemp LoadMaster deployments worldwide and says 80% of the Fortune 500 uses its software.

escape_quotes and the missing null byte

The bug lives in a small helper called escape_quotes(). It walks an input string, wraps any single quotes so a downstream shell command line will not close its own literal early, and returns the sanitised copy. The code allocates its output buffer with malloc(), which on glibc returns raw heap memory whose first bytes are whatever was there before: allocator metadata, freed strings, whoever's data was resident when that chunk got freed. Then it walks the input, writes the escaped bytes into the buffer, and returns without appending a null terminator. Two trivial mistakes in a twenty-line function. watchTowr Labs walked the diff and the entire fix in Progress GA 7.2.63.2 and LTSF 7.2.54.18 changes exactly two things: malloc() becomes calloc() so the buffer is zero-filled, and a *end = 0 line lands where the terminator was always supposed to go.

When the unpatched escape_quotes() returns, the caller receives a pointer to a heap chunk whose escaped quotes are correct and whose trailing bytes are whoever's data was next in line in the allocator's arena. A C string ends at the first zero byte, so if the buffer contains the escaped apiuser value and then twelve bytes of a neighbouring chunk before hitting a natural null, sprintf copies all of it into the command line that will be handed to system(). The apiuser the caller sent is now suffixed with attacker-controlled bytes that live in adjacent heap memory.

Two lines of fix, six weeks of exploitation. Progress shipped GA 7.2.63.2 and LTSF 7.2.54.18 in early June 2026. watchTowr's disclosure and a working PoC landed June 29. eSentire's telemetry logged the first exploit attempts the same day and kept counting them through August 4. The gap between the fix on the download page and the CISA KEV entry that finally made it a deadline was two months.

How the attacker seats the payload

The overflow is the primitive; the exploit is teaching glibc's allocator to place the attacker's bytes right next to the escape_quotes() buffer. The /accessv2 endpoint deserialises its JSON body permissively, so extra top-level keys are not rejected. The exploit body sends the real apiuser key, then a run of decoy keys named g0, g1, g2, and so on up to g60, each carrying a string of the same shape and size engineered so the JSON parser drops it into the freelist bin the escape function will draw from a few frames later. Spray sixty and you cover the neighbouring slot with high probability.

The string each gN carries starts with a semicolon, then a shell command, then no closing quote. When sprintf reads past the escaped apiuser and into the neighbour, the resulting command line has attacker-supplied text after the metacharacter that terminates the intended argument, and system() parses a well-formed command line and runs it. Root, no authentication, one request. Independent write-ups and SecureLayer7's technical breakdown agree on the mechanism.

Why the CVSS 9.6 sorts your LoadMasters wrong

The 9.6 is honest. What the base score cannot tell you is which LoadMaster it is. A management interface bound to an internal admin VLAN behind a jump host is a very different box from one facing the public internet with the API listening on 0.0.0.0, but the CVE score is identical on both. A patch window driven by that score treats them as identical, so the appliance that already has weeks of exploit traffic against it lines up behind the one that has never seen a hostile packet. Base score is a property of the vulnerability, not the deployment, and it cannot separate a five-minute upgrade window from an appliance already being sprayed.

Four TRIS layers that separate two identical LoadMasters

TRIS is the Threat and Risk Intelligence Scoring engine inside CVEasy AI. It scores an event against your inventory so the same CVE lands in different bands on different appliances.

Exploitation status. Confirmed in the wild. eSentire logged 792 exploit attempts from 65 unique IP addresses in 18 countries over the 41 days ending August 4, 2026, and CISA moved the CVE to KEV three days later. Top band ACT applies. A working proof of concept alone would not have put it there; sustained real-world traffic did.

Exposure surface. A LoadMaster with /accessv2 reachable from the public internet sits at ACT. Restrict the management API to an internal admin range at the firewall and it drops several bands, and bind it to a private management interface with no external route and it drops further. Same CVE, three queue positions.

Downstream blast radius. The layer that separates a load balancer from a plain web server. TRIS walks what sits behind each LoadMaster: whether it fronts Exchange or a login page, what TLS keys are on the appliance, what backend service accounts are configured, and what routes to a Domain Controller VLAN look like from the appliance's shell. A LoadMaster terminating SSL for corporate SSO carries far heavier weight than one proxying a public marketing site.

Recovery cost. If a vulnerable appliance was reachable during the exploitation window, patching alone is not the response. Everything the shell could touch becomes a rotation and reissuance job: private keys for every TLS certificate the appliance terminated, cached backend service account credentials, and any admin account that ever authenticated to the box. The gap between a five-minute LoadMaster upgrade and a two-day certificate and secret rotation is the actual work your team is committing to.

What to do this week

The fix has been on the download page since June. If your LoadMaster is on GA 7.2.63.1 or LTSF 7.2.54.17 or older and its management API has been reachable from anywhere untrusted, assume compromise. Exposure alone is optimistic. A pre-auth root shell on a load balancer terminating TLS is a certificate rotation job, and the certificate rotation is the work that determines when you can call it done.

1. Upgrade. Move to LoadMaster GA 7.2.63.2 or LTSF 7.2.54.18. Progress shipped both in early June 2026, so the patch has been sitting on the download page for two months.

2. Restrict /accessv2 at the network layer. Even after patching, the management API should not accept arbitrary internet callers. Push it behind an upstream firewall or ACL scoped to trusted admin ranges, and use this incident to confirm every appliance actually follows that baseline.

3. Hunt the request signature. Pull LoadMaster and upstream network logs for POSTs to /accessv2 in the 41 days before August 4, 2026. Bodies with long runs of top-level keys named g0, g1, and up, or an apiuser field packed with single-quote content and semicolons, are the indicator.

4. Rotate on any confirmed hit or exposed unpatched box. Regenerate the LoadMaster's TLS private keys and reissue certificates for every virtual service it terminates, rotate any backend service account whose credentials the appliance stored, and force reset every LoadMaster admin account. Do not skip the certificate step: an appliance running as root can read the keys off disk, and no log entry proves that a shell did not.

How CVEasy AI answers this on your own hardware

CVEasy AI is the number one local-first CTEM platform. It ingests advisories from watchTowr Labs, eSentire, and CISA KEV alongside NVD, matches affected LoadMaster versions against your inventory, and runs each finding through TRIS against your network posture and traffic graph. Output is a short list per appliance: which LoadMasters are on a vulnerable branch, which have /accessv2 reachable from outside your admin range, which show the anomalous POST pattern in the last 45 days, and which backend routes each holds keys or service credentials for. Your inventory, versions, and request logs never leave your infrastructure, which is the point when the finding is that a box in your rack is one crafted JSON body away from a root shell.

Sources: watchTowr Labs, CISA KEV addition, The Hacker News, eSentire advisory, SecurityWeek, SecureLayer7, Cyber Security News

A CVSS 9.6 on your queue does not tell you which LoadMaster is on fire

CVEasy AI ranks each appliance by real exposure, live exploitation, and downstream blast radius, so the box already being sprayed jumps the box that never sees a hostile packet.

Related Reading