On September 22, 2026, security firm DepthFirst published a working exploit that takes an unprivileged process inside a default Docker or Kubernetes container straight to an interactive root shell on the host. The bug, CVE-2026-80521 (CVSS 7.8), is a use-after-free in the Linux kernel's AF_UNIX socket garbage collector. Upstream fixed it on August 6. But Ubuntu's security tracker, last updated October 13, still lists its 24.04 and 26.04 kernels as "Vulnerable, work in progress" — no fixed package to install, three weeks after a public exploit, ten weeks after the upstream patch.
If you run tenant containers on your own nodes, that sentence is your whole quarter: there is no patch, the exploit is public, and the vulnerable code is reachable through system calls your workloads make every second. Here is the patch-gap runbook: the exposure check, who is fixed, what to do without a kernel, and the rollout for the day one ships — each expanded below.
Step 1 — Check exposure. Run this on every node (it usually works from inside a container too, since there is only one kernel):
grep -cE ' unix_(add|del)_edges$' /proc/kallsymsA count above zero means the rewritten garbage collector is present and the node needs a verdict from your vendor's tracker, not from its version number. Where fixes stand:
| Distribution | Kernel | Status |
|---|---|---|
| Ubuntu 26.04 LTS | linux + cloud kernels | Vulnerable, no fix (Oct 13) |
| Ubuntu 24.04 LTS | linux + cloud kernels | Vulnerable, no fix (Oct 13) |
| Ubuntu 22.04 LTS | linux 5.15 | Not affected (check HWE kernels separately) |
| Debian 13 trixie | 6.12 | Fixed in 6.12.111-1 (DSA-6528-1) |
| Debian 12 bookworm | 6.1 (6.1.176-1) | Vulnerable, no fix yet |
| Amazon Linux 2023 | 6.18.35 | Livepatch Sept 30 (ALAS2023LIVEPATCH-2026-397) |
Step 2 — Triage. A container escape still needs code execution inside a container first. Find every workload on affected nodes that runs code you did not write: CI runners building fork pull requests, multi-tenant namespaces, notebooks and code-runner features, and any pod with a known unpatched remote-execution bug.
Step 3 — Blunt it. Default seccomp, user namespaces, rootless containers, and dropped capabilities do not stop this exploit — the vulnerable code is reachable with no special privilege. Until a kernel ships, move the workloads from Step 2 behind a stronger boundary (gVisor, Kata Containers, or a separate VM/node pool on an unaffected kernel).
Step 4 — Roll the fix. When your vendor ships a kernel: pin it in your node image, roll it one node at a time with cordon-and-drain or a machine rollout, re-run the check, and then decide whether the sandboxes from Step 3 stay or go.
That is the whole plan; what follows is the evidence and the traps that catch fleets that skim it.
What the bug actually is
Unix-domain sockets can pass open file descriptors between processes, and a socket can even be sent over itself — so the kernel needs a garbage collector to find groups of sockets that reference only each other and free them. Linux 6.10 replaced that collector with a new design that tracks sockets as a graph of vertices and edges, grouped into strongly connected components.
The new collector has a race. While one thread publishes a fresh edge during a multi-descriptor sendmsg, another thread can close the sockets involved; the collector then frees a vertex but leaves it linked in a cached component list, and the next collection pass touches freed memory. The upstream fix, credited to reporter Kyle Zeng, unlinks the component entry before freeing the vertex. That one-line change is the entire difference between a safe kernel and a container escape.
Why this matters more than most kernel bugs: creating Unix sockets and passing file descriptors are everyday operations. Docker's default seccomp profile allows them, and so does the RuntimeDefault profile, because nearly all software needs them. The exploit reaches the kernel through ordinary, permitted system calls — which is exactly why namespace isolation, cgroup limits, and seccomp filtering all fail to contain it. DepthFirst's published exploit targets one specific Ubuntu 26.04 kernel build, but the vulnerable code spans every kernel carrying the new collector.
The gap in numbers
Put the dates in a row and the shape of the problem is obvious:
| Date | Event |
|---|---|
| July 24, 2026 | DepthFirst wins a Google kernelCTF slot with the exploit |
| August 5, 2026 | Reported to the kernel security team (independently confirmed by an OpenAI researcher) |
| August 6, 2026 | Fixed upstream (mainline plus stable backports) |
| August 26, 2026 | CVE publication date |
| September 22, 2026 | DepthFirst publishes the working exploit |
| September 30, 2026 | Amazon Linux ships a livepatch |
| October 2, 2026 | Still no fixed Ubuntu 24.04/26.04 or Debian 12 kernel |
| October 13, 2026 | Ubuntu tracker last updated: 24.04 and 26.04 still "Vulnerable, work in progress" |
Two things stand out. First, the window between upstream fix and public exploit was seven weeks — anyone tracking stable kernels had time to prepare, and anyone waiting on a distribution kernel had time to worry. Second, the window between public exploit and distro fix is now open-ended: three weeks and counting for the two most common self-hosted node images, with no published ship date. Upstream has fixed the 6.12, 6.18, and 7.1 lines, but as of early October there was still no fix at all in the 6.1 and 6.6 long-term branches — which is why Debian 12, on the 6.1 line, is stuck regardless of how fast Debian's own security team moves.
This is also the third container escape of the year, after Copy Fail (CVE-2026-31431) and Fragnesia. Treat the sandboxing in Step 3 as potentially permanent infrastructure, not scaffolding you tear down the day a kernel lands.
Step 1: are your nodes exposed?
Version numbers mislead on distribution kernels, in both directions. Ubuntu 24.04 ships a 6.8 kernel; upstream 6.8 never had the new garbage collector, so a naive version check says "not affected" — but Ubuntu's tracker says vulnerable, because distribution kernels pull stable-branch backports (the same backport stream that carried the new collector into 6.6, starting at 6.6.93, and 6.1, starting at 6.1.141) into their own trees. Conversely, a distribution can backport the one-line fix and keep the old version number, so "old version" does not prove "vulnerable" either.
So check for the code itself. The rewritten collector adds two functions, and the kernel lists its symbols in /proc/kallsyms, which is world-readable with addresses zeroed for unprivileged users — and visible from inside an ordinary container, because container and host share one kernel:
grep -cE ' unix_(add|del)_edges$' /proc/kallsymsAbove zero means the new collector is present; combine that with your vendor's tracker for the verdict. (Hardened setups can mask that file; gVisor and Kata sandboxes have their own kernels.)
Fleet-wide, start with the inventory you already have, then confirm per node:
kubectl get nodes -o custom-columns=NAME:.metadata.name,OS:.status.nodeInfo.osImage,KERNEL:.status.nodeInfo.kernelVersion
kubectl debug node/<node-name> -it --image=busybox:1.36 -- \
grep -cE ' unix_(add|del)_edges$' /proc/kallsymsThe debug pod shares the node's namespaces, so it needs matching RBAC and admission-policy clearance; delete it when done. One more trap: early reports listed Ubuntu 22.04 as vulnerable, but the tracker marks its 5.15 kernel not affected — the 5.15 line never received the new collector. The 22.04 HWE kernels are newer and tracked separately, so check them by name rather than assuming the LTS verdict covers them.
On RHEL rebuilds, Azure Linux, Container-Optimized OS, Bottlerocket, or Talos, the same procedure applies but the verdict comes from that vendor's tracker.
Step 2: triage who runs code you did not write
With no patch available, the operative question is who can get arbitrary code execution inside a container on your affected nodes. Rank the usual suspects by how directly strangers control the code:
- CI runners and build agents that execute pull- or merge-request code from forks. A malicious PR is already code execution; on a vulnerable node it becomes host root.
- Multi-tenant clusters where teams or customers deploy their own images. Any tenant is one exploit away from every other tenant's data on that node.
- Notebooks, online code runners, plugin systems, and "run your script" features. Arbitrary user code is the product.
- Any pod with a known remote-code-execution bug you have not patched yet. The escape turns an app-layer RCE into a node takeover.
Single-tenant nodes running only your own images still need the kernel when it ships, but they are not where you start — an attacker with no path to code execution cannot reach the bug. This triage is also the durable security win from the incident: most fleets discover during Step 2 that they cannot actually enumerate which workloads run untrusted code. Write that list down; you will reuse it for the next escape.
Step 3: what actually blunts it with no patch
Start with the honest negatives, because the obvious mitigations are the trap. DepthFirst and Canonical have published no workaround that closes the attack surface, and the reasons are structural:
- Default seccomp does not help. The default profiles allow Unix sockets and descriptor passing. This is not a misconfiguration — blocking them would break nearly everything.
- Blocking AF_UNIX with a custom profile is not a general fix. For the Copy Fail bug earlier this year, blocking one rarely used socket family was a clean mitigation. AF_UNIX is different: DNS resolution through NSS, database clients on local sockets, process managers, logging, and many language runtimes all use it. Blocking it breaks most real applications. A custom profile can still make sense for one specific workload you have tested without Unix sockets — but that is surgery per workload, not a fleet policy.
- Rootless containers, user namespaces, and dropped capabilities do not help. They are good hardening and you should keep them, but the vulnerable code is reachable without any special privilege, so they change nothing about exploitability here.
- Updating Docker, containerd, runc, or Kubernetes does not help. The bug is in the host kernel; no runtime upgrade touches it.
Tighter seccomp and AppArmor profiles, fewer privileged containers, and restricted capabilities still reduce blast radius in general — apply them, but recognize they reduce rather than eliminate this exposure.
What does work is a different isolation boundary for the workloads from Step 2:
- gVisor runs the container on a user-space kernel that implements Unix sockets itself, so the sandbox's sockets never touch the host kernel's garbage collector. On GKE this is GKE Sandbox; elsewhere, install
runscon the nodes, register it as a containerd runtime handler, and select it with a RuntimeClass. Test first: gVisor does not implement every system call, and I/O-heavy jobs can run slower. - Kata Containers runs each pod in a lightweight VM (optionally under Firecracker). The guest kernel may carry the same bug, but a successful escape lands inside the VM, not on the host.
- A separate node pool on an unaffected kernel — Ubuntu 22.04 with its 5.15 kernel is the obvious candidate — for untrusted workloads until your main image is fixed. Short-term measure with real tradeoffs (older kernel, different hardware support), not a destination.
A RuntimeClass plus a pod that uses it looks like this:
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: gvisor
handler: runsc # the containerd runtime handler configured on the node
---
apiVersion: v1
kind: Pod
metadata:
name: untrusted-build
spec:
runtimeClassName: gvisor
containers:
- name: build
image: registry.example.com/ci/build-runner:2026.10Step 4: when the fix lands — pin, roll, re-check
A fixed kernel package does nothing until the node boots into it, so the fix landing upstream — or in your vendor's archive — starts a rollout project, not a victory lap. For a Cluster-API-managed fleet on owned machines, the sequence is:
- Pin the fixed kernel in your node image. Do not
apt upgradeyour way out of a kernel CVE on live nodes and call it done; bake the fixed package version into the image your machine deployments reference, so every future scale-up and replacement inherits it. Record the fixed package version next to the CVE in your runbook. - Roll one node at a time. Cordon and drain, reboot into the new kernel (or replace the machine via a rolling machine-deployment update), uncordon, and move on. Bound the blast radius of a bad kernel exactly as you would bound the exploit: never reboot the fleet at once.
- Re-run the Step 1 check against the new image in your pipeline and against each rolled node, this time asserting the fixed package version rather than just the symbol presence. Keep the check in the image pipeline permanently — it is cheap, and the next AF_UNIX-class bug will reuse it.
- Decide the sandboxes' fate. With the kernel fixed, the gVisor/Kata routing from Step 3 becomes optional. Given three container escapes in one year, keeping untrusted workloads sandboxed is the defensible default; at minimum, keep the RuntimeClass and the triage list from Step 2 so the next patch gap starts from a runbook instead of a blank page.
One special case: if your fleet runs Amazon Linux 2023 on the matching kernel, the September 30 livepatch applies without a reboot once kernel livepatching is enabled — verify it actually applied rather than assuming the package presence equals protection.
The self-hosted lesson
On a managed control plane, this entire incident is someone else's quarter: the vendor absorbs the patch window invisibly, reboots your nodes on their schedule, and you read about it afterward. That is a genuine operational advantage, and this post does not pretend otherwise.
But notice what the self-hosted fleet gets in exchange. You choose the kernel, so you can move untrusted workloads to an unaffected pool today instead of waiting on a vendor's rollout train. You own the node image pipeline, so the exposure check becomes a permanent gate rather than a one-off scramble. And you control the reboot sequence, so the fix lands on your maintenance windows instead of the vendor's.
The price is exactly what this post describes: during the gap, the triage, the sandboxing, and the rollout sequencing are yours. There is no third party to absorb them — but also no third party standing between you and the fix the day it ships.
Keep the check, keep the triage list, and keep the sandboxes warm. The next one is already in the stable queue.
Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Star the repo on GitHub or deploy your first app today.



