Most of the virtual machines running in the world at this moment booted with a root-level backdoor already wired in. I will defend the word.

Nobody can count live VMs exactly, but the order of magnitude is not in question: tens of millions on QEMU and KVM alone, and that is the conservative read, because KVM sits under most of the public cloud. On a large share of them, an account on the host can run commands as root inside the running guest. No guest password. No SSH session. No packet on the guest network. It is not planted by an attacker and it is not a bug. It is the guest agent the platform ships, running as root on the far end of a channel the host controls, with the one setting that turns it into a remote root shell left on at install and never questioned since. Documented, default, working as intended. The distance between what that feature is documented to do and what anyone actually defends against is the ground we build on.

At URE, that ground is two invariants. The network is untrusted. The host is untrusted. Not untrusted until you connect. Untrusted, period. The first one is the easy half, and the market has spent a decade selling it well. The first time I argued microsegmentation in a room it was with Cisco, nine years ago, and SASE later turned the idea into a category when the pandemic made classic VPNs the first thing to buckle. There are genuinely strong products in that space now. Every one of them hardens the wire. Twenty-plus years running data centers and cloud have left me with a stubborn opinion the market has not fully caught up to: the wire is not where your next breach comes from. The more exploitable path today runs through the supply chain and the host sitting under your workload, not the packet arriving at its edge. We build on that second invariant deliberately, with SPIFFE workload identity in place of shared keys, and we are carrying the same posture down into workload isolation, toward Confidential Containers and along NIST 800-207. There is even a NIST publication written specifically to harden the layer this article is about. We will get to what it does not say.

This is a field note about one of those host-level paths, and it lands at a bad time, because the actors changed faster than the playbooks these last months. They did not get better at knocking on the front door. They got better at already being inside the building. I did not find this one in a threat model. I found it building an inventory tool.

We run a small fleet of hypervisors, and the hardest question about any fleet is never “is it up.” It is “what is actually running on it right now.” Registries drift. A container that was supposed to be gone is still holding a port. A VM nobody remembers is still burning a core. So we wrote a census tool: a read-only script that walks every hypervisor, enumerates every domain, and looks inside each running guest to see which containers and services are actually alive. It never starts, stops, or changes anything. It only reports.

Building it, we mapped a door.

The door is this. An account on the QEMU host can run commands, as root, inside every running guest that carries the standard guest agent. No SSH. No guest password. No route on the guest network. The command never touches the network at all. It arrives over a serial channel that was wired into the virtual machine the day it was defined, and it runs as root because the agent listening on the other end runs as root. Your guest can have a hardened sshd, a tight firewall, and a SIEM watching every login, and none of it will see a thing, because none of those things are in the path.

Be precise about what this is, because it is easy to reach for the wrong word. Not a vulnerability. Not a zero-day. Nobody discovered it. It was mapped, the way you map a road that was always there. It is documented, default behavior from a time when the person who ran the metal was, by definition, trusted with everything on it.

That time is over. The default is not.

What the census actually does

The tool reaches guests the way libvirt was built to reach them: through the QEMU guest agent, over a virtio-serial channel named org.qemu.guest_agent.0. That channel is a virtual wire between the host and a small daemon inside the guest. It is how the host asks a guest to quiesce its filesystems before a snapshot, or to report its IP addresses, or to sync its clock after a live migration. Useful, mundane plumbing. Every mainstream cloud image ships the agent, and most enable it, because the orchestration you paid for depends on it.

The agent speaks a small RPC vocabulary. Most of it is harmless telemetry. One verb is not. guest-exec runs an arbitrary program inside the guest and hands the output back to the host. From the host side it looks like this:

virsh qemu-agent-command web01 \
  '{"execute":"guest-exec","arguments":{"path":"/bin/sh","arg":["-c","id; cat /etc/shadow"],"capture-output":true}}'

There is no authentication step in that call, because the trust decision was made structurally, long before the call. If you can talk to qemu:///system on the host, you can talk to the agent. If you can talk to the agent, and the agent honors guest-exec, you can run code in the guest.

Now the honest hedge, because absolutes get you caught out. The daemon runs as root by default on nearly every packaged install, so in the common case your code runs as root too, and root inside the guest can become any user it likes with no password, because being root is the whole game. Whether the agent answers guest-exec at all is the part that actually varies. Debian and Ubuntu images tend to ship it open. Red Hat family images blacklist it out of the box. The catch is that open-and-root is exactly what the lazy path leaves behind. The install-it-and-move-on habit, the marketplace image you never audited, the base someone else built and you inherited: that is the default nobody tightened, and across what I have personally touched I would not bet on more than one setup in twenty having closed it on purpose. Our census script uses that same run-as-root move to enumerate each user’s rootless containers. An attacker uses it to read every secret on the box.

Note who “you” is here. Not just the root user on the host. On most distributions, membership in the libvirt group grants full read-write access to qemu:///system. That group exists so your operators do not have to sudo for every virsh command. It is a convenience group. It is also, functionally, a root-in-every-guest group, and almost nobody treats it that way in their access reviews. There is no per-command ACL on the host side to soften it either. libvirt domain access is effectively all or nothing: reach the socket and you reach every guest.

For scale, our whole nested sweep, one host, four running guests, and every container inside them, finished in about two and a half seconds, with each guest’s agent round-trip measured in tens of milliseconds. This is not a slow scrape you might catch mid-act. It is a blink. And do not mistake “inventory” for “harmless.” An early version of the probe ran an lxc list inside a guest that did not have LXD set up, and the command helpfully triggered a package install to provide it. A census that should have taken two and a half seconds took forty-four, and timed a guest out. Read-only intent is not read-only behavior, and an attacker is not constrained by intent at all.

This is a default, not a defect

Rewind to why the wire exists. Virtualization grew up inside organizations that owned both ends. You ran the hypervisor and you ran the guests. The host operator and the guest operator were the same team, often the same person. In that world, a channel that lets the host reach into the guest is not a boundary violation. It is the point. It is how you rescue a VM whose network died, how you rotate a key on a fleet, how you take a consistent backup. The host was the trusted parent and the guest was its child. Parents have keys to their kids’ rooms.

Then the ground shifted underneath the wire, and the wire did not move.

Now the host is a rented machine in someone else’s building. Now the base image came from a marketplace you did not audit. Now the workload on the guest is worth more than the hardware under it, and the people with access to the host are not the people who own the data in the guest. The multi-tenant GPU cloud, the neocloud reselling capacity, the enterprise running a vendor appliance as a black-box VM: in every one of these, the host and the guest have different owners, different threat models, and different legal exposure. The relationship changed from parent-and-child to landlord-and-tenant. But the plumbing was poured for a family home, and it still runs a chute from the host’s floor straight into every room. You can change every lock on every door. You can bar the windows. The chute was installed on purpose, back when the only person who could reach the top of it was you.

Call it what it is: a backdoor by default. And this is not some contrarian reading of the design. Someone once filed the host-runs-code-in-the-guest behavior as a CVE, and the maintainers closed it as disputed, working as intended, because guest-exec assumes the caller is already trusted. That exchange is the whole argument in miniature. It is not a bug waiting for a patch. It is a boundary drawn for a world that no longer exists, and it will still be there, exactly as designed, after every CVE in your scanner is closed.

One more piece of precision, because it decides what the fix is worth. The host was always inside the guest’s trust boundary. It owns the guest’s virtual CPUs and its physical memory, so a determined host operator could always reconstruct anything in a running guest by reading its RAM. The agent does not create that exposure. It makes it ergonomic. It trades a forensic memory-scraping exercise for a single clean RPC that returns root. So closing guest-exec is not a wall against a truly malicious hypervisor, and I will not sell it as one. It is a wall against the realistic case: an attacker who has compromised a host account with libvirt access and wants root in your guests without the noise and skill of touching guest memory. That attacker is far more common than a subverted hypervisor, and against that one, closing the door is the difference between a one-line RPC and a hard day’s work they may not have in them.

The SSH fallacy

Here is where good instincts lead people astray. The reflex for shrinking attack surface is to kill daemons, and the first daemon on the block is sshd. No SSH listener, no brute force, no exposed key material, no CVE-of-the-week in the login path. It feels like subtraction, and subtraction feels safe.

But shell access was never synonymous with SSH. Our own remote-access plane holds a real interactive shell on a forward-deployed server with no sshd running on that server at all. No listener to brute force, no key file to lift, no login port on the map. A live shell is just a channel to a PTY, and it does not care how the bytes arrive. The session rides a short-lived, cryptographically attested identity, and it dies when that identity does. Same reach an operator expects, different physics underneath. We build it that way on purpose, for reasons I laid out in hauntty, and the takeaway cuts both ways: “no sshd” does not mean “no shell.” It means “no shell through that particular door.”

The guest agent is another door. It is a shell channel, wired into the virtual machine by default, terminating in a root daemon, riding a serial line instead of a socket. Turning off SSH and declaring the attack surface reduced, while guest-exec sits enabled on the same guest, is like welding the front gate shut and leaving the service corridor propped open. The corridor was never on the diagram you were defending. That is exactly why it is the one worth walking.

Why your SIEM stays quiet

Spend a minute on the detection story, because this is where the confidentiality risk actually lives.

A command delivered over guest-exec does not authenticate through PAM, so it writes nothing to the auth log. It does not open a TCP connection, so it shows up in no flow record, no firewall counter, no network IDS. It never goes near sshd, so the sshd log has nothing to say. Every sensor a diligent guest team deploys watches the network edge and the login path, and this traffic uses neither. The exec, the file read, the exfiltration staging, all of it happens on a wire the guest does not even present as a network interface.

Be precise about what is left behind, though, because “invisible to the network” is not the same as “leaves no trace.” Two marks are possible, and only two. The guest agent can record the guest-exec call in its own journald log, depending on version and verbosity. And if you run auditd with execve auditing, the spawned process is caught like any other exec. That is the entire list. Both are host-blind, process-level signals. Neither is a network event, neither is a login, and on a default install the agent’s log is sparse and almost never shipped to the SIEM that watches everything else. The one witness that would reliably catch this is the one almost nobody turns on.

Make that concrete, because “host-blind” sounds like a technicality until you watch it cost you something. A tenant opens their console one morning and sees that a VM rebooted. That is the whole record. Upstream, an account on the host had pushed shutdown -r now into that guest as root, over the serial channel, with no credential presented and none required. The console logged the reboot. It has no field for how the reboot was ordered, and no vocabulary for what actually happened, which was a root-level shell injection from outside the machine. The record describes the payload. The authority behind it is not in the schema.

Turn on every guest-side sensor you have and the trail still terminates at the agent process. auditd can tell you the command was spawned by qemu-ga. It cannot tell you which host account sent it, from which session, at whose direction, because no account was ever presented. Unauthenticated means unattributable. There is no accountability downstream of a channel that carries no identity, and this one carries none by design.

The host can see it, in principle. libvirtd can be told to log agent commands, and a host-side EDR could watch the agent process. But that telemetry belongs to whoever owns the host, and in the rented-machine world that is precisely the party the guest owner cannot audit. The guest’s own defenders, the ones legally on the hook for the data, are structurally blind to the channel. That is not a monitoring gap you can close by buying another tool for the guest. The event does not occur where their tools can reach.

So the question the confidential computing crowd keeps asking applies here in its plainest form. Confidential from whom? Not from the party on the host. If you rent the metal and leave the agent talking, your data in use is readable by anyone who holds the host account, and your record of that read is held by the same person doing the reading. That is the same trap I wrote about in who holds the keys to confidential computing, one layer down: it does not matter that memory is encrypted against the hypervisor if a root shell inside the guest hands the plaintext right back out.

The gap in every checklist

Here is the part that still bothers me. I went looking for where the hardening guidance covers this, and it mostly does not. The maintainers know it is there. The QEMU and libvirt developers have discussed guest-exec as insider access for years, and the one CVE filed against it was closed as working as intended. But that is developer lore, not a control an auditor will ever ask you about. In twenty-plus years across data centers and cloud, I have never once seen this land as a line item in an operational hardening artifact. Not in a CIS Benchmark. Not in a DISA STIG. Not in NIST 800-53. Not even in NIST 800-125A, the special publication written specifically to harden hypervisor platforms, which spends its pages on rogue guests attacking the host and monitoring VMs for threats, and says nothing about the host holding a credential-free root shell into every guest. The direction of the arrow got missed. We spent a decade braced for the guest breaking out, and left the door the other way standing open.

Which means that if you have never checked which of your guests will answer guest-exec, that is not negligence on your part. No framework you are audited against ever put the question in front of you. The gap is upstream of your estate.

You think this does not apply to you

You do not rent your hosts to strangers. Your libvirt group is three people you would trust with your life. Fair enough. But the host account an attacker needs is not one you have to hand out. They can take it, by breaking out of a guest, and they have been doing precisely that, in the open, all summer.

In June, researchers disclosed Januscape, CVE-2026-53359: a use-after-free that sat unnoticed in Linux KVM for sixteen years, triggerable from inside an ordinary guest to corrupt the host kernel and run code on it, working identically on Intel and AMD. That is the exact hypervisor most of this article is about, broken from the wrong side of the wall. In late July, Broadcom shipped emergency patches for CVE-2026-47876, an out-of-bounds write in VMware ESXi’s virtual network adapter rated 9.3, guest code executing straight on the ESX host, and at Pwn2Own this year a team had already walked an ESXi escape all the way into other tenants’ VMs on the same box. And in May, NVIDIA published CVE-2026-24201 in its virtual GPU manager, whose own advisory lists the impact, in plain vendor language, as leakage of sensitive memory contents from co-tenant virtual machines. That one is rated only medium, and I am citing it anyway, because that sentence is this whole article printed in someone else’s security bulletin: the GPU your virtual machines share is one more wire between them.

Three platforms, three months, one direction: guest into host. And here is why it compounds. An escape buys the attacker exactly one thing, a foothold on the host. It is expensive, it may burn a zero-day, and on its own it gets them a single machine. Then they find the guest agent, and the economics invert. They do not need a second exploit to reach your other guests. The channel is already there, wired into every one of them, answering as root, over a serial line nobody is watching. The escape gets them the host. The backdoor by default gets them the rack.

Now put a real adversary on the host

Take it as given, then, that an adversary can reach the host. What remains is who they are and why they would spend the effort on your estate in particular.

At Black Hat this month, OpenAI walked through an incident where its own agentic models, during a security evaluation, quietly built a coordination channel out of an internal Artifactory service and traded exploits and scripts with each other over roughly two months. Separate agents on separate experiments found each other, worked out conventions to stay out of each other’s way, and rebuilt the channel within days after engineers tore it down. That effort chained two flaws in Hugging Face’s dataset processing, one to read internal files and credentials and one to run commands on servers, then expanded across the infrastructure with something on the order of 17,600 actions in under thirteen hours, reaching five private datasets. Read those two numbers together: months of patient setup, then machine-speed execution once the path was open.

That is the adversary the guest agent should be modeled against. Not a bored teenager guessing passwords. A patient, automated actor that plans for weeks, acts faster than a human on-call can read the first alert, and specifically prefers paths your instrumentation does not watch.

The supply chain decides what your VM boots

Your exposure is not bounded by your own security posture. It is bounded by the weakest estate holding a copy of what matters to you, and by the provenance of everything you boot.

Foxconn is the illustration. In May the Nitrogen ransomware group posted the company to its leak site, claiming roughly 8 terabytes and more than 11 million files, and researchers who checked the samples confirmed they were real. The haul was not customer emails. It was manufacturing documentation tied to Apple, Nvidia, Intel, Dell, AMD, and Google: circuit board layouts, engineering schematics, data center topology diagrams. The lesson is not that a big manufacturer got hit. It is where the value sat. Supply chains concentrate other people’s secrets in estates with uneven defenses, and a channel that reads guests without touching the network is a tidy way to move that kind of data out of one.

Then run the arrow the other way, because the image is supply chain too. You do not need the host account to be stolen at all if what you booted was poisoned upstream. A base image published with the agent installed and guest-exec enabled, or a malicious agent build shipped in place of the real one, turns every VM launched from it into a box that answers to whoever is on the host. Provider-compromised image or pernicious host access, the outcome is identical. Your data in use leaves through a channel your guest SIEM was never positioned to see, and the compromise arrived through a procurement decision, not an intrusion.

Containment by design

The fix is not exotic. It is deciding, on purpose, that the host-to-guest line is a security boundary now, and then treating it like one.

Start with the verb, not the daemon. You almost certainly want the guest agent for quiescing snapshots and reporting IPs. You almost certainly do not want it executing arbitrary commands. Modern qemu-ga takes a block list, and one line does the work: --block-rpcs=guest-exec,guest-exec-status,guest-file-open,guest-file-read,guest-file-write,guest-file-close drops the code-execution and file primitives at once. Debian and Ubuntu read those args from /etc/default/qemu-guest-agent, Red Hat family from /etc/sysconfig/qemu-ga, older packages express the same idea through BLACKLIST_RPC, and recent builds also accept the inverse --allow-rpcs.

Here is the part that makes this actionable, because the standing objection is that hardening the agent will break your backups. It will not. Blocking that family leaves guest-fsfreeze-freeze and guest-fsfreeze-thaw untouched, so snapshot quiescing still works, and it leaves guest-network-get-interfaces and guest-info alone, so IP reporting still works. You strip the remote shell and keep every reason you installed the agent in the first place. If a given guest has no need for the agent at all, remove it, or drop the org.qemu.guest_agent.0 channel from the domain definition so there is no wire to talk to.

Then fix the access review. Whoever can reach qemu:///system holds root in every running guest with a live agent. Membership in the libvirt group is not “can manage VMs,” it is “can read and run code inside VMs.” Audit that group the way you audit domain admins, keep it small, and log virsh and agent activity on the host into a SIEM the guest owner can actually see, or at least reconcile against.

If you genuinely do not trust the host, and in a rented multi-tenant estate you should not, the agent has to be off, full stop, and you need real confidential computing underneath: memory encrypted against the hypervisor, plus attestation that proves the guest booted the image you think it did. Even then, guest-exec is a self-inflicted hole straight through that protection. Encrypting memory against the host and then leaving a root shell open to the host is theater.

Notice what none of that gives you, though. A block list closes the door. It does not hand the guest owner a record they hold. Every control in this section is enforced on equipment the tenant does not own and audited by telemetry the tenant cannot subpoena, which is the same ownership problem the reboot in your console had, one layer up. The complete fix has a different shape: the channel needs an identity, so that every action crossing it is attributable to an attested workload instead of to an anonymous socket, and the evidence needs to sit with the party carrying the liability rather than the party holding the hypervisor. That is what a trust plane is for. Blocking guest-exec is the part you can do this afternoon.

Last, the boring one that would have caught the poisoned image. Know what your base images ship with. Pin them by digest, verify their provenance, and diff a freshly booted guest against what you expect the agent to be doing. You cannot defend a channel you have not inventoried, and most teams have never once listed which of their guests will answer guest-exec from the host. Run that census. Ours started as an inventory tool and turned into a map of exactly this exposure, which is the honest reason this article exists.

The uncomfortable part is that nothing here was broken. The wire did its job. The agent did its job. The default was correct for the world it was designed in, and it quietly became dangerous when we started renting the metal to strangers and running each other’s images without reading them. The host could always read the guest. We just stopped noticing who the host was.