No CVE Required: The Ted Backdoor Hiding Inside Your Own HAProxy Build
Rapid7 Labs published a report on 4 September 2026 describing a Linux implant they found compiled directly into the HAProxy binary at two South Korean organisations, one automotive, one media. The attackers named it in their own debug strings: ted. It isn’t a HAProxy vulnerability. There’s no CVE, because there’s nothing in HAProxy’s code to patch. Getting it onto a box in the first place needs code execution and root already, and once it’s there, the fix that would normally apply, upgrade the software, does nothing at all.
What HAProxy is doing when this happens
If you’ve read the Ansible Deep Dive lab post on this site, you’ve already stood one of these up: a load balancer sitting in front of a pool of backends, terminating connections, deciding where each request goes. That position is exactly what makes it worth compromising. A load balancer sees every request before anything else does, and its own statistics are usually the first place anyone looks to ask “did anything unusual come through here.” Ted’s whole design is built around the fact that both of those are true.
How it actually works
The attackers recompiled HAProxy 2.8.12 with a custom filter plugin built directly into the source tree, hooking HAProxy’s own HTTP parser rather than sitting beside it. A request to one specific image path flips the connection into command-and-control mode. From there, the implant reaches into HAProxy’s internal counters, active connections, cumulative request counts, byte totals, and decrements them by exactly the amount its own traffic added. The session that just happened gets subtracted back out of the load balancer’s own bookkeeping. It then writes the command body into a named pipe under /tmp, zeroes out what’s left in the request channel so HAProxy has nothing left to forward, and the request terminates right there. No backend ever sees it, so no backend ever logs it.
The response comes back over the same raw socket, wrapped in an ordinary HTTP/1.0 200 OK header, which is what makes the whole exchange look like unremarkable web traffic on the wire. Through that channel an operator can beacon, push or pull files, run shell commands, or replace the implant’s own configuration.
For content tampering, a request has to clear four separate checks before it gets served a modified page: a User-Agent has to be present and match, the target file path is chosen based on architecture markers in that same header, the URL and referer both have to match a configured rule, and then either the client’s IP has to appear on an allowlist (checked both as an exact address and as a /24 subnet) or an operator key hidden inside the Accept-Language header overrides the IP check entirely. Once a request clears all four, the implant swaps the response body using HAProxy’s own body-editing calls, the same internal mechanism a legitimate filter would use, rewrites the Content-Length and Content-Type to match, and strips the Accept-Ranges header so a client can’t request a byte range and notice the size changed underneath it.
The same toolkit included a trojanized sshd that intercepts plaintext passwords and writes them to an encrypted log, plus trojanized crond, agetty, atd, and polkitd binaries carrying a companion RAT Rapid7 calls curlRAT. The fake crond inherits the file-creation timestamp of /usr/bin/ssh so it doesn’t stand out in a directory listing, and a stager scrubs the keywords tmp, wget, cron, and crond out of six system logs, auth.log and audit/audit.log among them, right after installing it.
The line that actually matters
Rapid7’s report makes a point of stating plainly what their own recommended defence can’t yet do: “a recompiled HAProxy build reports the identical version string as a clean build,” and they publish no detection rule for that specific check. Their own advice is independent network correlation, memory behavioural analysis, and binary integrity checks, in that order, but the third one is the one with no tooling attached to it in their own writeup.
That’s the part worth sitting with longer than the mechanism itself. Every other CVE this site has covered this year has had a version number attached to the fix. Upgrade, and the vulnerable code is gone. Ted doesn’t work that way. The vulnerable code was never HAProxy’s to begin with. Upgrading replaces a trojanized binary with a different trojanized binary that happens to be built against newer source, unless whatever process installs it also verifies what’s actually running against something other than its own reported version string.
Attribution, held at arm’s length
Rapid7 attributes the toolkit to North Korean state actors with medium confidence, and it’s worth reading exactly how they get there rather than taking the headline at face value. The domain list is credited to APT37 by two independent trackers, maltrail and ThreatFox. The delivery model, a compromised edge component serving altered content to selected visitors, overlaps with Operation SyncHole, a Lazarus campaign Kaspersky documented separately. The suspected initial access vector, an exposed Groupware portal, a class of Korean enterprise software, points at a third cluster, Kimsuky, based on unrelated research from ENKI. APT37 and Lazarus are assessed by Mandiant to sit under different parts of the North Korean state apparatus entirely. Rapid7’s own conclusion: “further evidence is necessary to make a more definitive assessment.”
Tracing it back further, the domain-to-APT37 link in maltrail cites two posts on X from July 2025, one published three hours before the other. That’s a thin, if not unreasonable, foundation for a chain that ends up spanning three separate threat clusters. None of this makes the attribution wrong. It makes it worth remembering that “medium confidence, attributed to state actor X” is doing a lot of quiet work in a sentence like that, and the actual evidentiary chain underneath it is usually a lot shorter than the confidence label implies.
What would actually catch this
Network-side visibility, the kind this site has spent a lot of time on, genuinely struggles here. The C2 traffic never becomes an anomalous flow. It’s a normal-looking request to an image path, answered with a normal-looking 200 OK, on a connection that HAProxy’s own counters insist never happened. rst-forensics classifies resets by origin, and Watching the Fabric covers SLA and flow observability, but both of those tools are built to notice traffic behaving unusually. Ted’s entire design goal is traffic that behaves exactly like all the other traffic around it, on a box whose own telemetry has been told to agree.
This is the same lesson NatJack already made about NAT tables: once an attacker can edit the state a device uses to describe its own activity, that state stops being evidence of anything. HAProxy’s connection counters and NatJack’s NAT table are the same category of problem wearing different clothes, the audit trail and the thing being audited turn out to be the same piece of memory.
What’s actually needed is something checking the box from outside its own reporting: file integrity monitoring that hashes the binary independently of what the binary claims about itself, and something watching for exactly the anti-forensics behaviour Rapid7 documented, timestomped files, selectively edited logs, a service binary that doesn’t match its package manager’s record. This site already has a small, real answer to that question, not a theoretical one. Part 6 and Part 7 of the Pi rebuild series stood up a Wazuh manager and confirmed its file integrity module was already running the same job AIDE would have done, no extra install needed. That build was watching a Raspberry Pi, not an internet-facing load balancer, and it wasn’t purpose-built for a threat model like Ted’s. But the category of tool it demonstrates, something with an independent, tamper-resistant view of what a binary actually is rather than what it reports itself to be, is precisely the missing piece in Rapid7’s own writeup. It’s the same reason a proper host-based intrusion detection build, watching binaries as well as logs, keeps coming up as unfinished business on this site’s own list.
If you’re running HAProxy, or any edge component that terminates traffic before it reaches an application server, the practical takeaway isn’t “patch it.” There’s nothing to patch. It’s knowing what your binary’s hash is supposed to be, checking it against something other than the binary’s own version string, and treating that edge component with the same suspicion you’d apply to anything else with root and a direct line to the internet.
Sources: Rapid7 Labs: TR: DPRK APTs’ TED Backdoor & curlRAT Target South Korean Media, Automotive Sectors · The Hacker News: New Ted Backdoor Hides Inside Victims’ Own HAProxy Builds to Intercept Web Traffic