Linux BPF Verifier Scalar-Forking Soundness Bug to Container Escape — CVE-2026-31413
by Rat5ak · 2026-07-05
- Severity
- Critical
- CVE
- CVE-2026-31413
- Category
- binary
- Affected product
- Linux kernel — BPF verifier (maybe_fork_scalars())
- Affected versions
- 6.12.75+ (stable backport dea9989a3f) through 7.0-rc4; introduced by bffacdb80b93 (Linux 7.0-rc1), fixed by c845894ebd6f (Linux 7.0-rc5)
- Disclosed
- 2026-07-05
- Patch status
- patched
Archive entry
intelseclab/poc-archiveMetadata
| Field | Value |
|---|---|
| Date Added | 2026-07-05 |
| Last Updated | 2026-04 |
| Author / Researcher | Rat5ak |
| CVE / Advisory | CVE-2026-31413 |
| Category | binary |
| Severity | Critical |
| CVSS Score | Not specified in source |
| Status | Weaponized |
| Tags | linux-kernel, ebpf, bpf-verifier, container-escape, modprobe-path, gke, lpe, vtable-hijack |
| Related | N/A |
Affected Target
| Field | Value |
|---|---|
| Software / System | Linux kernel — BPF verifier (maybe_fork_scalars()) |
| Versions Affected | 6.12.75+ (stable backport dea9989a3f) through 7.0-rc4; introduced by bffacdb80b93 (Linux 7.0-rc1), fixed by c845894ebd6f (Linux 7.0-rc5) |
| Language / Platform | C, Linux kernel (eBPF), container runtimes (tested against GKE nodes) |
| Authentication Required | Local-only (requires CAP_BPF + CAP_PERFMON + CAP_NET_ADMIN, e.g. inside an unprivileged-but-capable container) |
| Network Access Required | No |
Summary
The Linux BPF verifier’s maybe_fork_scalars() forks verifier state when it sees an ARSH followed by AND/OR with a constant. The forked (“pushed”) path is generated via push_stack(env, env->insn_idx + 1, ...), which skips the ALU instruction on that path and assumes the destination register is 0. This assumption is correct for AND (0 & K == 0) but wrong for OR (0 | K == K) — so the verifier believes a register holds 0 while the CPU actually computes K. This register-value divergence lets a BPF program with CAP_BPF/CAP_PERFMON/CAP_NET_ADMIN pass verifier bounds checks it should not pass, yielding an out-of-bounds read/write primitive against a BPF map. The included exploit chain leaks the map’s kernel address, forges a fake bpf_map_ops vtable, redirects a map operation to achieve arbitrary write, and overwrites modprobe_path to execute an attacker script as root when the kernel handles an unknown binary format — achieving full container-to-host escape.
Vulnerability Details
Root Cause
push_stack(env, env->insn_idx + 1, ...) in maybe_fork_scalars() causes the verifier’s forked/pushed exploration path to skip the ALU instruction that generated the fork, incorrectly retaining the pre-fork register value (0) instead of the true post-ALU value. For BPF_OR operations this produces a soundness bug: the verifier’s tracked register state (0) diverges from the actual runtime value (K), invalidating every subsequent bounds check that depends on that register.
Attack Vector
- Load a BPF program (with
CAP_BPF/CAP_PERFMON/CAP_NET_ADMIN, obtainable inside certain container configurations) that performsARSH 63(producing{0, -1}), thenORs with a constant, followed by a conditional branch that causes the verifier to fork state. - On the forked path, add the “zero” register (verifier believes
0, CPU computesK) to a BPF map pointer; the verifier approvesmap_value + 0while the CPU executesmap_value + K, yielding an out-of-bounds map access. - Use the OOB read/write primitive to leak the map’s kernel address (
poc/leak_map_addr.c,poc/step1_leak_ops.c–step3_arb_read.c), then build a fakebpf_map_opsvtable and redirectmap_push_elemthrough a controlled pointer (exploit/exploit.c,exploit_or_fork*.c) for arbitrary kernel write. - Overwrite
modprobe_pathwith an attacker-controlled script path. - Trigger execution of an unknown binary format, causing the kernel to invoke the attacker’s script via
modprobe_pathas root. - Inside a container, this yields full host root and container escape (GKE-specific variants included as
exploit_gke.c/exploit_gke_v2.c).
Impact
Arbitrary kernel read/write from a BPF program with limited capabilities, escalating to root code execution on the host and full container escape.
Environment / Lab Setup
Target: Linux kernel 6.12.75+ .. 7.0-rc4 (container with CAP_BPF + CAP_PERFMON + CAP_NET_ADMIN, e.g. GKE node)
Attacker: gcc/make (Makefile provided), root inside the container to load the BPF program
Proof of Concept
PoC Script
See
poc/(bug validation:validate_bug.c,test_oob.c,leak_map_addr.c,step1_leak_ops.c,step2_oob_rw.c,step3_arb_read.c) andexploit/(exploit.c,exploit_gke.c,exploit_gke_v2.c,exploit_ctf.c,exploit_or_fork*.c, plus post-exploitationtier2–tier10modules) in this folder, along with the upstreampatches/fixing the bug.
| |
The poc/ programs incrementally validate the verifier bug and the OOB read/write primitive; exploit/exploit.c (and its _gke/_gke_v2 variants targeting Google Kubernetes Engine nodes) chain the primitive into a full container-escape achieving host root via modprobe_path overwrite. patches/ contains the upstream one-line verifier fix and accompanying selftests that were merged into mainline.
Detection & Indicators of Compromise
Signs of compromise:
- Unexpected changes to
/proc/sys/kernel/modprobe - BPF programs loaded from container workloads that should not require
CAP_BPF/CAP_PERFMON/CAP_NET_ADMIN - KASAN/kernel OOB warnings referencing BPF map access shortly before a privilege escalation event
Remediation
| Action | Detail |
|---|---|
| Primary fix | Apply upstream commit c845894ebd6f (Linux 7.0-rc5) or update to a kernel build incorporating the one-character maybe_fork_scalars() fix (patches/0001-bpf-Fix-unsound-scalar-forking-in-maybe_fork_scalars.patch) |
| Interim mitigation | Restrict CAP_BPF/CAP_PERFMON/CAP_NET_ADMIN from untrusted container workloads; enable seccomp/BPF-program-loading restrictions where feasible |
References
Notes
Mirrored from https://github.com/Rat5ak/CVE-2026-31413-BPF-Container-Escape on 2026-07-05. The upstream repository also includes a demo video and additional post-exploitation “tier” modules (credential overwrite, syscall hooking, anti-forensics, persistence, etc.) beyond the core verifier-bug PoC; the large demo video was omitted here per archive size/media conventions, but all C source (exploit chain, validation PoCs, and post-exploitation modules) and the upstream kernel patches are included.