An autonomous agent with a shell has superpowers. It installs packages, runs scripts, opens connections and fixes its own mistakes, without waiting for anyone. Nobody reviews each command. That’s the point.
It’s also a big attack surface: every command it chooses, every package it pulls, every script a web page talks it into.
Give an agent a shell, and the boundary is the only reviewer left.
So I run every agent in its own VM. This week, a guest VM got root on its host anyway. The first step was telling the host kernel where to write a checksum. The write-up, published on 7 November, targets Firecracker. I read it with one question: could this happen in Koala?
It can’t, and the reason is a design choice worth checking in any VM setup.
First, what a checksum offload is #
Every network packet carries a checksum. Computing it costs CPU, so virtio lets the guest hand that job to the host: “the checksum starts here, write it there.” That shortcut is an offload, and it’s on by default in most fast VM networking.
It also means the host kernel reads two numbers the guest wrote.
Anything the guest writes is input. What matters is where it gets parsed.
How the escape worked #
- The way in. A bug in the host kernel’s IPv4 code trusted those two numbers. With crafted values, the guest could read host memory 32 bytes at a time. The authors also report small writes in their lab.
- The escape. They used that access to rewrite a Firecracker vCPU thread’s saved registers. That Firecracker ran as root with no jailer and no seccomp, so it meant root on the host.
The kernel fix landed upstream on 14 October 2026. The bug gets patched. The pattern stays.
Where your guest’s packets get parsed #
The attack needs guest packets to reach the host kernel’s network stack with the hints attached. TAP and vhost-net, the usual fast paths, do exactly that. Koala uses neither.
- Frames stay in userspace. Each VM’s network card hands its frames to
koala-net, a small process that runs as you, not root. It handles them withnetstack , the network stack from Google’sgVisor , used as a library. Only the network stack: the isolation boundary is still the VM. - Traffic leaves through ordinary sockets. When policy allows a connection,
koala-netopens a normal socket. The host kernel builds those packets itself. - The Mac works the same way. Apple’s Virtualization framework also hands frames to
koala-netin userspace.
The host kernel never parses a frame the guest built.
Two bits, and a test that keeps it that way #
A virtio device and the guest agree on features at boot. Koala’s network device offers only two that reach the guest: a MAC address and modern virtio. No offloads, so the guest can’t even send the hints.
You can see it from inside a running VM. Bit 0 comes first:
$ koala exec dev -- cat /sys/bus/virtio/devices/virtio5/features
00000100000000000000000000000000100000000000000000000000…
That was true from day one. But a property nobody tests can disappear the day someone turns offloads on for speed. So now:
- A unit test fails if the device offers anything else, or accepts any of 13 offload features. Adding one as a trial broke it straight away:
offered 0x1400000a0, want 0x140000020. - A check in a real VM reads the bits from inside the guest and fails on anything but 5 and 32. It passes 5/5 today.
- Both run on every Linux build. Wiring that up also found a test that had never run on Linux. That’s its own post.
If something else gets in #
The escape’s second step, hijacking the hypervisor, meets the second wall. Each VM’s Cloud Hypervisor runs as your user, under Landlock, seccomp and no_new_privs, and can’t open network sockets.
To be honest about the limit: code that can already write host kernel memory doesn’t need the hypervisor, and no userspace sandbox stops it. What protects Koala here is the first wall. The sandbox is for the next bug. A boundary has to hold against tomorrow’s bug, not just today’s.
And patch your host kernel anyway. Docker, or any VM tool that uses TAP, can still reach this one.
The cost, honestly #
| TAP with offloads | Koala | |
|---|---|---|
| Who parses guest frames | Host kernel | koala-net , in userspace |
| Who does checksums | Host kernel, on the guest’s word | The guest |
| CPU per byte | Lower | Higher |
| Built for | Moving huge amounts of data | Agents |
For bulk data, that’s a real cost. Agents aren’t that workload. They call model APIs, fetch pages and clone repositories. For an agent, how far its traffic can reach matters more than how fast it goes.
What I’d take from this, beyond Koala #
- A shell is a superpower. An agent that can run anything will eventually try anything. Build the boundary for that.
- Know where the host reads the agent’s data. Find every place where data from the agent is read by the host. That’s where the wall is weakest.
- Agree to as little as you can. Every feature the host agrees to is one more thing that can break.
- Turn properties into tests. “Offloads are off” used to be just true. Now the build breaks if anyone turns them on.
- Say what you gave up. Koala trades some speed for a smaller attack surface. Say that openly, so readers can decide if the trade fits them.
Check your own setup #
- Where are guest packets parsed? If it’s the host kernel through TAP or vhost-net, offload hints are attack surface.
- Run
cat /sys/bus/virtio/devices/*/featuresin the guest. Count the set bits. - Is the hypervisor running as a normal user, sandboxed? This escape needed root and no seccomp.
- Which of these properties does a test enforce?
Koala runs each AI agent, or any Linux workload, in its own VM on your Mac or Linux machine. Everything here is the default. The latest release is 0.1.0-rc.2:
brew install kunalkushwaha/koala/koala
Agents get more capable every month. Set the boundary now, for tomorrow’s agent and tomorrow’s bug.