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.
Contents
  1. The news
  2. Were we exposed?
  3. Forge: the firewall wasn't guarding Docker
  4. The vault's master key was in the agent's files
  5. Backing up the vault, and hearing when it breaks
  6. Still open

1. The news

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:

Our daily security-research job flagged it by email that morning. What follows is what we did that day.

2. Were we exposed?

Container escape path and which lab hosts were exposedA process in a container reaches the shared kernel's AF_UNIX garbage collector bug and becomes root on the host. Forge, the GB300 and both DGX Sparks run affected Ubuntu kernels; the Macs and Synology do not.One kernel bug turns any container into root on the host A container any app, running as a normal (non-root) user Shared Linux kernel AF_UNIX socket garbage collector: use- after-free (CVE-2026-80521) Root on the host every other container, every file, every secret Where it applied in our lab (checked live, September 23, 2026): Forge (MS-01) Ubuntu 24.04 · kernel 6.8 · 34 containers, incl. the password vault GB300 Station Ubuntu 24.04 · kernel 7.0 nvidia-64k · 1 container 2× DGX Spark Ubuntu 24.04 · kernel 6.17 nvidia · 1 container each Macs + Synology NAS not Ubuntu kernels · not affected Not a remote bug: something must already be running code in a container. Real fix = Ubuntu's patched kernel + a reboot. Until then: shrink who and what can get in.

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:

  1. 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.
  2. Image updates. Five of Forge's images track :latest. Nothing pulls them automatically (no Watchtower), so they only change when someone pulls on purpose.
  3. 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:

Forge firewall and database access, before and afterBefore: Docker-published ports bypassed the host firewall and the Supabase Postgres superuser kept its default password on the LAN. After: a Docker firewall filter limits ports to the home subnet, and default-password accounts only work inside Docker.Forge: the host firewall wasn't guarding Docker BEFORE AFTER Any device on the home LAN Any device on the home LAN Host firewall (ufw) Docker-published ports go around it New Docker firewall filter home subnet only · starts at boot · 5-minute auto- revert while testing Container ports on every interface vault · databases · dashboards Container ports reachable from the home LAN, nothing else Supabase Postgres superuser still on its factory-default password, reachable from the LAN Supabase Postgres default-password accounts: Docker network only · outside: one strong-password account kept in the vault Supabase is further limited to the M4 and the three family Mac minis. Verified after: default-password logins refused from the LAN, the host and loopback; every Supabase service reconnected cleanly.

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:

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.

How the vault master password leaked, and the fixBefore: the vault master password lived in an agent skill file, flowed into every session and was saved in long-term memory. After: the agent has its own least-privilege vault account, the master password and admin token were rotated, and memory was cleaned.The vault's master key was sitting where the agent could read it BEFORE AFTER Owner's vault master password the key to every stored credential Master password changed owner-only, kept outside the vault Pasted into an agent skill file so scripts could unlock the vault Agent has its own vault account User role, one shared collection: can read and edit, can't manage members Loaded into every agent session model context, session logs, command lines Unlocked by a small wrapper password in an owner-only file, never in chat, logs or argv Copied into long-term memory the memory layer saved 11 secrets as ordinary facts Admin token rotated; memory cleaned container holds only an Argon2 hash · 11 memory entries deleted Old copies still exist in logs, but the master password and admin token they hold no longer work. One API key that also leaked into memory is still on the rotate list.

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 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

Nightly vault backup pipeline and alertsA 03:45 job makes a safe live copy of the vault database, checks it, bundles everything a restore needs, keeps 14 daily and 8 weekly copies, and the existing NAS backup carries it off the box. Failures, big item drops and missed runs all email.Vault backup: nightly, checked, and loud when it breaks 03:45 every night after the other nightly database dumps Safe live copy SQLite online backup, no downtime Checked integrity check · item-count guard Bundled database, keys, config, run script · 14 daily + 8 weekly Off the box Forge's existing NAS backup carries it Alerts (quiet on a good night): Any step fails ERROR email from Forge >20% of items vanish ALERT email; old backups are kept, not rotated away Backup never ran 08:30 check from another machine emails ERROR if no fresh backup Tested: a clean run, a faked item-count drop, and a forced failure all behaved; one alert landed in spam first.

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

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.