Sep Security Work: a container-escape bug, and what it shook loose
Created September 23, 2026 · James Meadlock and Milo (written in a session on anthropic/claude-opus-5-5, reasoning enabled) · home lab
Exposed Ubuntu hosts4 of 4
Kernel fix shippednot yet
Secrets out of memory11
Vault backupsnightly
Where it stands (September 23, 2026). Ubuntu has not shipped a fixed kernel for this bug, so every Ubuntu box in the lab is still exposed in principle. What changed today is how much a successful escape could reach, and how hard it is to get code into a container in the first place. The kernel patch and reboot come when Ubuntu marks its packages fixed.
On September 23, 2026 The Hacker News ran "Exploit Released for Unpatched Ubuntu Linux Flaw Enabling Host-Root Container Escape". The bug is CVE-2026-80521, a use-after-free in the Linux kernel's AF_UNIX socket garbage collector. Local sockets are what processes on one machine use to talk to each other and hand each other open files. A race while cleaning those up frees memory the kernel keeps using. From inside an ordinary container, with syscalls Docker and Kubernetes allow by default, that becomes root on the host.
The facts that matter, from primary sources:
Upstream fixed it on August 6, 2026. DepthFirst found it with their in-house model and used it to win a Google kernelCTF slot on July 24. OpenAI reported the same bug independently. DepthFirst published the writeup and exploit code on September 22 ("Containers Are No Longer a Security Boundary").
Ubuntu's tracker (CVE-2026-80521, last updated September 21) rates it Medium, CVSS 7.8, local attack vector. 24.04 LTS is Vulnerable, 26.04 is work in progress, 22.04 and older are not affected.
It is not remote. Something has to already be running code on the box or in a container.
Our daily security-research job flagged it by email that morning. What follows is what we did that day.
2. Were we exposed?
Checked live over SSH, read-only. On every Ubuntu host the running kernel has the newer AF_UNIX garbage-collector code the fix changes. The exploit's own test target was Ubuntu 26.04's generic 7.0 kernel; the GB300 runs the same 7.0 series in NVIDIA's 64k flavor.
Yes, on every Ubuntu box. None of them has a fixed kernel available yet, so the useful questions were: how could untrusted code get into a container here, and what would it reach if it did?
How code could get in, for a home lab like ours, in order of likelihood:
Model code. The GB300 serves a model with --trust-remote-code, which runs Python shipped with the model. The current model is fine. The rule until the patch lands: no new model repos with remote code, and no new nightly serving images.
Image updates. Five of Forge's images track :latest. Nothing pulls them automatically (no Watchtower), so they only change when someone pulls on purpose.
An exposed service. The router has no port-forwards and none of these boxes runs a tunnel, so this means something on the LAN, not the internet.
What it would reach: on the GPU boxes, one serving container and its weights. On Forge, 34 containers, including the household password vault. Forge is where we spent the day.
3. Forge: the firewall wasn't guarding Docker
The audit found problems that don't need a kernel bug at all:
Docker ports bypass the host firewall. Forge runs ufw with sensible rules, but Docker installs its own firewall rules ahead of it. Every port published on all interfaces was open to anything that could reach the box, whatever ufw said. The hook Docker provides for exactly this, the DOCKER-USER chain, was empty.
A factory-default database password on the LAN. The self-hosted Supabase stack's Postgres superuser still had the Supabase CLI's default password, and its port was reachable from the whole home network.
Two containers already amount to host root. One Supabase logging container mounts the Docker socket, and cAdvisor runs privileged with the host filesystem mounted.
The filter was applied with a 5-minute auto-revert armed, tested from an allowed host and a blocked one, then made permanent as a boot-time service. The Supabase stack stays running; it is locked down, not removed.
Two details worth copying:
Test from a host that should be blocked. An allowed machine getting through proves nothing on its own. We checked from a Spark: it could still reach the vault and dashboards, and every Supabase port refused it.
You can't just change the default Supabase password. The Supabase CLI hardcodes postgres for its local stack, so changing it would break the next supabase start. Instead, Postgres's own access rules now accept the built-in accounts only from inside Supabase's Docker network. Everything outside uses one new strong-password account, stored in the vault. A small script reapplies the rule after every reboot. Afterwards, default-password logins were refused from the LAN, from the host, and from loopback, and every Supabase service reconnected with no auth errors.
4. The vault's master key was in the agent's files
This one was on us. To let Milo read credentials from the self-hosted Vaultwarden vault, the owner's master password had been written into one of the agent's skill files. That file loads into agent sessions. So the password had reached the model's context, session logs and command lines, and the long-term memory layer had saved it, along with 10 other secrets, as ordinary facts about the owner.
The agent now gets exactly the access the job needs: read and edit one shared collection, no member management, no permanent deletes. Unlocking goes through a wrapper so the password never appears in its context or logs.
What changed:
The agent got its own vault account. The owner created an organization, moved the shared items into one collection, and invited the agent as a plain User with Can edit. The agent's account and API key were created without a human ever seeing its password. The API key lets it log in without email codes.
The owner changed the master password. A tip for anyone doing this: the first attempt edited a saved login named "Vaultwarden Master" inside the vault, which changes nothing about how you log in. The real setting is under Settings → Security → Master password. The server's own database showed the difference immediately: stored hash unchanged, and not a single password-change request in the log.
The admin-panel token was rotated, and the container now holds only an Argon2 hash of it. The old token is rejected, the new one works, and it lives in the vault.
11 memory entries containing secrets were deleted, found by searching the memory layer with several different phrasings.
The general lesson: a credential an agent can use without you is a credential an attacker can use through the agent. Hiding it better doesn't change that. Scoping what it unlocks does.
5. Backing up the vault, and hearing when it breaks
Each nightly bundle holds everything a restore needs: the database, the server's signing key, its config, and the script that recreates the container. The vault's items are encrypted client-side, so the backup file doesn't reveal passwords on its own.
Forge already had a whole-machine NAS backup, but a vault deserves its own: restorable in minutes, with history, and checked every night. The item-count guard exists for one scenario: a bad sync or mass delete that nobody notices until the last good copy has been rotated out. When the count drops by more than 20%, the job emails an ALERT and stops deleting old backups.
A backup that fails silently is worse than none, because you think you have one. So the job emails on failure, and a separate machine checks every morning that a fresh backup exists. That covers the case where the job never ran at all. One practical note: the first test alerts landed in the recipient's spam folder. Test your alert path end to end, including the inbox.
6. Still open
The kernel patch. When Ubuntu marks its packages fixed: upgrade and reboot Forge. On Forge, the boot default is pinned to the current kernel, so installing a fixed one won't boot it until that pin is changed. The GB300 gets a planned window. The Sparks have to move to the 7.0 NVIDIA line regardless, because their current line is no longer maintained.
The two root-equivalent containers on Forge (the Docker-socket mount and privileged cAdvisor). They are LAN-only now, but still there.
One API key that leaked into memory still needs rotating.
The longer-term fix. DepthFirst's point stands: a container is not a security boundary between things you trust and things you don't. The vault shouldn't share a kernel with 33 other containers. It belongs in its own VM or on its own box.
Bottom line. The CVE was the prompt, but not the biggest finding. The kernel bug needs a patch we can't ship ourselves. The audit it forced turned up three problems we could fix the same day: a firewall that wasn't covering Docker, a factory-default database password on the LAN, and the vault's master key in an agent's files. Each was fixed and then verified from the outside. A day with an unpatched CVE was a good day to find them.