Blog / Threat Analysis · CVE

CVE-2026-31431 ("Copy Fail") — TLCTC Analysis

Updated to reflect heise.de reporting of 2026-05-04: in-the-wild exploitation confirmed, CISA alert issued, public PoCs available, distro patches shipped. The TLCTC classification of the underlying flaw does not change — the new information adds chronology, urgency, and the surrounding attack paths in which the kernel primitive is now being chained.

BK
Bernhard Kreinz
Loading read time...

1. Chronology of the disclosure

Dates verbatim where the source provides them; relative phrasing converted where today's date (2026-05-04) makes it unambiguous.

Date (2026) Event
≈ mid-April Silent fix lands in the upstream Linux source tree (in-place AEAD path reverted to out-of-place). Source available roughly two weeks before public disclosure per heise.
Late April / pre-extended-weekend Coordinated public disclosure of CVE-2026-31431 ("Copy Fail"). CVSS 7.8. Theori publishes the technical write-up; multiple PoC variants appear on GitHub (theori-io repository).
2026-05-01 CISA issues alert.
2026-05-04 (heise, 08:44 UTC) Active exploitation confirmed in the wild. Greg Kroah-Hartman has shipped patches for 6.18.22, 6.19.12 and 7.0; backports to LTS branches in flight. Most major distributions have published fixed packages.

Two timing observations matter for downstream analysis:

  • Patch-gap window (~2 weeks) between the silent commit and the public disclosure. Standard pattern: attackers diff the upstream commit against the previous tree, identify the fix, derive the bug, and weaponise. The speed of in-the-wild appearance after disclosure is consistent with this reverse-engineering pathway, not with independent rediscovery.
  • Forensic invisibility. The exploit primitive writes only into the page cache. No on-disk artefact persists from the corruption itself; the on-disk /etc/passwd is unchanged. Detection requires either page-cache-vs-disk divergence checks or syscall-level visibility into AF_ALG + authencesn + splice() patterns.
Forensic invisibility

The corruption never touches disk. /etc/passwd on storage stays intact while the page-cache copy resolves UID=0 for the attacker's own username. Any detection that compares only on-disk state will miss the entire incident.

2. Underlying flaw — primary TLCTC classification

Unchanged from the original analysis.

Cluster #2 Exploiting Server, sub-cluster #2.2 (core function vector — internal processing/parsing flaws in a server-role component).

Reasoning chain, condensed:

  • R-ROLE. The Linux kernel, exposed via AF_ALG, receives and processes inbound requests from the attacker's unprivileged userspace process. The kernel is in server role for this interaction → #2, not #3.
  • #1 vs #2. A logic error in the in-place AEAD scatterlist construction is required for the write to land. An implementation flaw is present → #2 / #3, not #1 (no designed-feature abuse within intended boundaries).
  • #2 sub-clustering. Not socket-protocol parsing (#2.1), not delegated external processing (#2.3). The locus is the kernel's own internal AEAD processing logic; the upstream fix reverts the in-place optimisation, confirming core-function-logic placement → #2.2.

Generic vulnerability: code imperfection in server-side software (internal kernel processing path).

3. What the kernel primitive does, in one sentence

Four attacker-controlled bytes per shot are written into a page-cache page of any file the unprivileged process can read; the failed AEAD auth check returns EBADMSG but the scratch write has already landed.

The published exploit is a 732-byte Python script. From local unprivileged shell to root in under a minute. No race window, no kernel offset disclosure required, deterministic across distributions since 2017.

4. Attack paths now observed in the wild

The kernel exploit step is structurally a terminal privilege-escalation primitive: it requires prior local code execution as an unprivileged user and yields root (or host kernel control from a container). It therefore appears as the last technical step in a chain whose earlier steps come from the operator's preferred initial-access cluster. Four chains are currently realistic; all four end identically.

Notation: #2.2 is the kernel exploitation; |[kernel][@user→@kernel]| is the v2.1 intra-system boundary marking the userspace→kernel crossing. Δt values reflect typical operator pacing post-foothold.

Path A — Local foothold from a server-side compromise

Most common ITW pattern reported for opportunistic exploitation of Linux hosts running internet-facing services.

Path A — Server-side compromise → kernel privesc
#2 ||[api][@External→@Org]||                    (initial RCE: web app, edge appliance, etc.)
   →[Δt=minutes–hours]
#7                                              (webshell or implant established as service user)
   →[Δt=minutes]
#2.2 |[kernel][@user→@kernel]|                 (algif_aead primitive)
   →[Δt<1s]
   + [DRE: I — /etc/passwd page cache]
   → SRE: Loss of Control (root)
   + [DRE: C, I, A — host]
#2 initial RCE
Δt = minutes–hours
#7 webshell/implant
Δt = minutes
#2.2 algif_aead primitive
Δt < 1s
[DRE: C, I, A — host]

Path B — Container escape in multi-tenant infrastructure

This is the chain that elevates the CVE from "local privesc" to "cloud incident". The Linux page cache is shared across containers on the same host kernel; corruption of a host-readable file is observable in every sibling namespace. Containers are not a security boundary against #2 in the host kernel.

Path B — Container escape via host kernel
[any path delivering code execution into tenant container]
   
#2.2 |[kernel][@container→@host-kernel]|       (same primitive, escapes namespace by design)
   →[Δt<1s]
   + [DRE: I — host page cache, shared across tenants]
   → SRE: Cross-tenant compromise
   + [DRE: C, I, A — host and sibling containers]

Path C — Endpoint chain via phishing / malware

Where the targeted host is a Linux workstation or developer machine.

Path C — Phishing / malware → kernel privesc
#9 ||[human][@External→@Org]||                 (lure → user runs attacker code)
   →[Δt=hours]
#7                                              (stage-1 loader / dropper as user)
   →[Δt<1m]
#2.2 |[kernel][@user→@kernel]|
   →[Δt<1s]
   + [DRE: I — /etc/passwd]
   → SRE: Loss of Control
   + [DRE: C, I, A — host]

Path D — Supply-chain delivery to a build / dev / CI host

Particularly relevant given the public PoCs are small Python scripts — trivial to embed in a postinstall hook or a CI step.

Path D — Supply-chain → build host privesc
#10 ||[update][@Vendor→@Org]||                (poisoned package, TAE = install)
   →[Δt=seconds]
#7                                              (post-install hook executes)
   →[Δt<1m]
#2.2 |[kernel][@user→@kernel]|
   →[Δt<1s]
   + [DRE: I — /etc/passwd]
   → SRE: Loss of Control on the build host
   + [DRE: C, I, A — host, with onward supply-chain blast radius]

Notes on the chains

  • The su / login step that follows the /etc/passwd rewrite is not a separate #4 Identity Theft. The attacker is corrupting the authoritative identity data store, not presenting a stolen credential. R-CRED does not apply: there is no credential acquisition and no credential presentation — the kernel resolves UID=0 for the attacker's own username because the backing data has been falsified. This is a Loss-of-Integrity DRE flowing from #2.2, not a new step.
  • "Privilege escalation" is not a TLCTC cluster (SG4). It is the outcome of #2.2 plus the Loss-of-Integrity DRE.
  • All four paths share identical SRE and DRE structure once the kernel primitive fires. They differ only in the cause-side cluster delivering initial local code execution.

5. Bow-Tie placement

Position Element
Cause #2.2 Exploiting Server — algif_aead in-place scatterlist logic flaw
Generic vulnerability Code imperfection in server-side software (kernel internal processing)
SRE / Central event Loss of Control — kernel forced to write attacker-controlled bytes outside intended buffer
DRE (primary) Loss of Integrity — page cache of arbitrary readable file (canonical target: /etc/passwd)
DRE (containerised) Loss of Integrity — host page cache, propagating to all co-tenant namespaces
Consequence Full Loss of C-I-A on the host; cross-tenant compromise in shared-kernel multi-tenancy

6. Velocity & containment

  • Exploit primitive: Δt<1s. End-to-end privesc: <1 minute.
  • Velocity class VC-4 for the kernel step itself; surrounding chain velocity bounded by the initial-access cluster (typically VC-2 / VC-3).
  • Detection-only controls are structurally weak: the operation completes in a single syscall sequence and leaves no on-disk trace. CDE_max for behavioural detection is bounded by syscall-level visibility into AF_ALG + authencesn(hmac(sha256),cbc(aes)) + splice().
  • Cause-side prevention dominates the ECR ceiling.

7. Controls grouped by Bow-Tie position

Cause-side (against #2.2)

  • Apply the upstream kernel patch (6.18.22 / 6.19.12 / 7.0 + LTS backports as they ship). The in-place→out-of-place revert is the only control that closes the generic vulnerability.
  • Block AF_ALG for unprivileged workloads via seccomp profiles or --security-opt on container runtimes. Eliminates the entry path even while patching lags.
  • For multi-tenant: replace shared-kernel namespace isolation with a hardware/VM boundary for any workload running untrusted code. Containers are not a security boundary against #2 in the host kernel.

Cause-side (against the chains delivering local exec)

  • Path A: edge-service patching, WAF, server hardening (against #2).
  • Path B: image provenance, runtime admission control, drop ambient capabilities (against the various #2/#7/#10 paths into the container).
  • Path C: anti-phishing, mail gateway, user education (against #9); EDR/AV (against #7).
  • Path D: dependency pinning, signed packages, sandboxed builds, isolation of CI runners from production trust (against #10 at the TAE).

Consequence-side (after SRE)

  • File integrity monitoring that compares on-disk state to served page cache content — catches the /etc/passwd divergence that the exploit produces but does not flush.
  • auditd rules on UID changes, setuid binary modifications, and unexpected use of AF_ALG from non-privileged processes.
  • Host-level egress controls and process-tree anomaly detection to bound blast radius once root is achieved.

8. Cross-framework note

In MITRE ATT&CK this maps to T1068 (Exploitation for Privilege Escalation), a technique that conflates cause (server-side coding flaw) and effect (privilege escalation). TLCTC keeps these separate: the cause is #2.2, the effect is a Loss-of-Integrity DRE that enables the SRE. Dirty Pipe (CVE-2022-0847) is a different subsystem, same TLCTC class (#2.2). The clustering is stable across both incidents; the ATT&CK T1068 label is not.

9. Summary

CVE-2026-31431 is — at the level of generic vulnerability — a single #2.2 step. What changed between the original advisory and the 2026-05-04 heise reporting is the environmental context, not the classification: the silent fix has been public long enough for diff-based weaponisation, distro patches are shipping, CISA has issued an alert, and operators are chaining the primitive onto whichever initial-access cluster they already use. The four chains in §4 cover the realistic ITW shapes. All four end with #2.2 and the same SRE + DRE structure; defensive priority should be patching first, AF_ALG lockdown second, and detection investments aimed at page-cache-vs-disk divergence and AF_ALG syscall patterns rather than at the post-root behaviour, which is too fast and too varied to gate on.

The TLCTC lesson

The kernel flaw is one cluster, one sub-cluster: #2.2 Exploiting Server.

The chain shape is determined by the operator's initial-access cluster (#2, #9, or #10) plus #7, then a single #2.2 step at the userspace→kernel boundary.

Privilege escalation is the SRE outcome, not a separate cluster. R-CRED excludes a follow-up #4 because no credential is presented — the identity store itself is rewritten.

ATT&CK T1068 conflates cause and effect; the cluster mapping does not. Patch first, lock AF_ALG second, and invest detection where on-disk forensics fail: page-cache divergence and AF_ALG syscall patterns.

Final classification

CVE focus#2.2 Exploiting Server — Linux kernel algif_aead in-place scatterlist logic flaw
SRELoss of Control — kernel writes attacker-controlled bytes outside intended buffer
DRELoss of Integrity — page cache of arbitrary readable file (canonical: /etc/passwd)
VelocityVC-4 at the kernel step (Δt < 1s); end-to-end privesc < 1 min
Path A#2#7#2.2 + [DRE: C, I, A — host]
Path B[any code-exec into container] → #2.2 + [DRE: C, I, A — host and siblings]
Path C#9#7#2.2 + [DRE: C, I, A — host]
Path D#10#7#2.2 + [DRE: C, I, A — build host + onward blast radius]
ATT&CK refT1068 (Exploitation for Privilege Escalation) — conflates cause and effect; TLCTC keeps them separate
Sibling caseCVE-2022-0847 (Dirty Pipe) — different subsystem, same #2.2 classification
About the methodology

This analysis applies the TLCTC v2.1 framework: ten cause-oriented threat clusters, the Bow-Tie SRE/DRE separation, attack path notation with Δt velocity classes and v2.1 boundary operators (||...|| for system-edge crossings, |...| for intra-system crossings such as userspace→kernel). For framework definitions: tlctc.net.

Licensed under CC BY 4.0. Framework: tlctc.net · Source: github.com/Barnes70/TLCTC