
Research and detection guidance for CVE-2026-31431, an io_uring-based bypass of syscall monitoring. Provides detection rules for Tetragon, Falco, and Wazuh, plus hardening strategies.
For CVE-2026-31431 ("Copy Fail"), we demonstrated systematic weaknesses in mainstream security products by combining three bypass strategies: io_uring async I/O path, process splitting (fork + SCM_RIGHTS), and socket reuse. Through empirical testing, we proved these techniques can evade virtually all syscall-based detection tools.
io_uring submits requests via shared memory ring buffers, bypassing traditional syscall entry points. This means:
iou-wrk-XXXXX) execute operations inside the kernel without triggering audit_syscall_entry()socket(AF_ALG) can be bypassed via IORING_OP_SOCKET — seccomp only checks at syscall entry, and io_uring operations don't go through that entryBy using fork + SCM_RIGHTS (Unix domain socket fd passing), socket creation and splice operations can be placed in different processes:
same_field(audit.pid) correlation breaks — socket PID ≠ splice PID, CRITICAL rule doesn't fireThe original PoC creates a new socket per iteration (producing 40+ socket(AF_ALG) calls). Socket reuse creates only one listening socket; the loop calls accept() which doesn't produce new socket events. Rules based on count >= N are completely defeated.
io_uring path + splice + /etc/passwd + authenc algorithm + SCM_RIGHTS splitting + socket reuse
Under this combination: syscall-based tools are completely blind, process-level correlation is broken, count thresholds fail. Only kprobe convergence-point detection can catch this combination.
__sock_create(family=38) is an unbypassable convergence point for all paths (syscall and io_uring) — AF_ALG is the only userspace crypto API in the Linux kernel. No matter how attackers vary their approach, they must create an AF_ALG socket. Monitoring this function at the LSM level provides 100% recall and is unaffected by any variant.
Falco's native modern_ebpf driver only captures the syscall path. The krsi plugin is required — it uses fexit tracing on io_socket() and __sys_socket() kernel function exits to cover the io_uring path for AF_ALG socket creation. Recommended fallback rule:
- rule: AF_ALG Socket Created
condition: >
(evt.type = socket and evt.args contains AF_ALG) or
(evt.type = krsi_socket and krsi.domain = 38)
output: >
AF_ALG socket created (source=%evt.type domain=%evt.arg.domain
krsi_domain=%krsi.domain proc=%proc.name pid=%proc.pid)
priority: WARNING
tags: [cve-2026-31431, crypto, container_escape]
The recommended rule's detection approach: simultaneously covers socket events (syscall path, using evt.args contains AF_ALG string matching to bypass ENUMFLAGS32 type limitation) and krsi_socket events (io_uring path, using krsi.domain = 38 integer comparison). No count thresholds (defeated by socket reuse), no PID correlation dependency (defeated by multi-process splitting).
Note: The community ThreatBear rule's three defense layers are all bypassable — ENUMFLAGS32 type mismatch (evt.arg[0]=38 always false), socket reuse defeats count threshold (count=1 < 40), multi-process splitting breaks PID correlation. See Rule Bypass Analysis.
Wazuh relies entirely on auditd's syscall audit events. io_uring operations don't go through syscall entry, so auditd produces zero events and all 7 Wazuh rules fail. The same applies to Elastic Security Agent — syscall-entry-dependent products are structurally blind to the io_uring path. See Wazuh Limitations Analysis.
The bypass_demo/ directory contains conceptual descriptions of detection bypass approaches. Actual PoC code is for internal use only and not publicly distributed.
| Document | Content |
|---|---|
| VULNERABILITY.md |
| Document | Content |
|---|---|
| defense/HARDENING.md | 3-layer defense model: kernel config → seccomp → user namespaces; Docker 29.4.2 security analysis |
| Product | Detection Layer | Traditional Syscall | io_uring Path | Multi-Process Split | Socket Reuse | Assessment |
|---|
| Tetragon (kprobe) | Kernel function | ✅ | ✅ | ✅ | ✅ | Only full-chain coverage |
| Falco + krsi plugin | fexit/fentry | ✅ | ✅ | ✅ | ✅ | Needs krsi for io_uring; entry-only |
| Falco (modern_ebpf) | syscall tracepoint | ✅ | ❌ | ✅ | ✅ | io_uring completely invisible |
| auditd / Wazuh | syscall audit | ✅ | ❌ | ❌ PID broken | ⚠️ | io_uring blind + PID correlation broken |
| Elastic Security Agent | syscall | ✅ | ❌ | ⚠️ | ⚠️ | Same as Wazuh; syscall-dependent = blind |
| Root cause — overlay of three kernel changes, 9-step attack chain, page cache write characteristics |
| EXPLOIT_VARIANTS.md | 6 exploit variant dimensions — I/O path × data submission × target file × AEAD algorithm × process splitting × socket reuse |
| DETECTION_THEORY.md | Detection theory — convergence vs. divergence points, 4-layer detection architecture, multi-signal temporal correlation |
| Document | Content |
|---|
| detection/tetragon.md | Recommended — Tetragon kprobe, 5 probes covering traditional + io_uring, only full-chain detection |
| detection/falco.md | Falco 0.40.0 + krsi 0.1.0 configuration guide, krsi internals, troubleshooting |
| detection/wazuh.md | Wazuh + auditd three major limitations: io_uring blindness, PID correlation breakdown, page cache invisibility |
| detection/rule_bypass.md | ThreatBear rule bypass principles, recommended rule anti-bypass empirical verification |