Three things have landed since this bulletin was first
published. (1) Windows Subsystem for Linux 2 is
vulnerable. A fully-updated WSL2 install (kernel
6.6.87.2-microsoft-standard-WSL2, WSL version
2.6.3.0) is exploitable by the unmodified
Theori PoC, confirmed in
issue #96
on Theori's repo and acknowledged by Microsoft in
microsoft/WSL #40365.
Microsoft has stated the patched WSL2 kernel will ship via
Windows Update as part of the May 2026 Patch Tuesday rollout
on May 12. Until then, wsl --update alone does
not fix it; the kernel itself has to be updated, and the
fix isn't in the channel yet. See the new
WSL2 section below.
(2) CISA KEV listing. CISA added
CVE-2026-31431 to the Known Exploited Vulnerabilities catalog
on May 1, 2026, citing evidence of active exploitation. The
BOD 22-01 patch deadline for federal civilian agencies is
May 15, 2026.
(3) In-the-wild activity. Microsoft Defender
reports observing preliminary exploitation testing and
expects threat-actor activity to ramp over the following
days. Sysdig and Sophos have published independent
confirmations of reliable exploitation across major
distributions and have shipped detection rules.
Today, Theori's Xint Code team
publicly disclosed "Copy Fail",
CVE-2026-31431, a Linux kernel local
privilege-escalation flaw in the AF_ALG AEAD path.
The disclosed chain combines authencesn,
algif_aead, and splice() to produce a
controlled 4-byte write into the page cache of a readable
file, including the cached image of a setuid binary such as
/usr/bin/su. Theori's public PoC is a
732-byte Python script that targets
/usr/bin/su by default and was directly
demonstrated against Ubuntu 24.04 LTS, Amazon Linux 2023,
RHEL 10.1, and SUSE 16. The fix reverts the 2017
algif_aead in-place optimization through commit
a664bf3d603d, some distributions have fixed
kernels available now, but not all supported distro kernel
lines are patched yet (Debian's tracker, for example, still
lists trixie and trixie-security as vulnerable at time of
writing). Check the specific vendor tracker for your running
kernel package, not just the upstream version number.
The PoC is already public on GitHub, and a second
independent PoC plus a non-destructive detector have since
been published by other researchers.
The formal CVE record describes the kernel-side fix in dry
implementation terms and assigns CVSS scores in the 5.5 to 7.8
band; Theori's disclosure demonstrates the weaponized impact
and is the better operational severity reference. Treat any
multi-tenant Linux host, Kubernetes node, self-hosted CI
runner, or cloud-SaaS-running-user-code service as actively
exposed until patched.
The combination is unusually bad: multiple working
public PoCs (the original Theori 732-byte
/usr/bin/su variant plus a separately published
/etc/passwd variant), no race window or
version-specific tuning needed, and a primitive that crosses
container boundaries because the page cache is shared by
the host. Theori reports the same 732-byte Python PoC
worked unmodified across its tested Ubuntu, Amazon Linux,
RHEL, and SUSE systems, and argues that mainstream kernels
built between the 2017 change and the patch are broadly in
scope. Treat any multi-tenant Linux host, Kubernetes
node, CI runner, or cloud-SaaS-running-user-code service as
actively exposed until patched or the workaround is in place.
Confirmed by Theori (copy.fail): Copy Fail
chains a logic flaw in authencesn, through
AF_ALG and splice(), into a 4-byte
page-cache write. The primitive lets an unprivileged local user
modify the in-memory page cache backing of a setuid binary
(default target: /usr/bin/su), so the next
invocation of that binary executes attacker-controlled code as
root. The change is not persistent across reboot; the resulting
root shell is. Theori directly verified the exploit against
Ubuntu 24.04 LTS, Amazon Linux 2023, RHEL 10.1, and SUSE 16.
Confirmed by kernel / CVE records: the
resolved issue is in the AF_ALG AEAD path, specifically
"crypto: algif_aead, Revert to operating out-of-place".
The exploitability comes from the interaction among
authencesn, algif_aead in-place
handling, and splice()-fed page-cache pages. The
CVE record lists patch activity touching
crypto/af_alg.c, crypto/algif_aead.c,
crypto/algif_skcipher.c, and
include/crypto/if_alg.h; that is the scope of the
patch series, not a claim that the bug exists in all four
files. The mainline revert was committed April 1, 2026 and is
shipping in stable kernels 6.18.22 and 6.19.12; distributions
are backporting to their respective supported kernels.
Required: a local unprivileged user account
on the target. No network access, no kernel debugging features,
no pre-installed primitives. The kernel crypto API
(AF_ALG) ships enabled in essentially every
mainstream distro's default config, so the entire 2017-to-patch
window is in play out of the box.
Not required: a kernel offset table, a race window, or a heap spray. Theori specifically calls Copy Fail a "straight-line logic flaw" rather than the typical Linux-LPE class.
Who needs to act first
Theori's own copy.fail page categorizes affected workloads by operational priority. Reproduced and lightly summarized:
| Priority | Workload class | Practical risk |
|---|---|---|
| High | Multi-tenant Linux hosts | Shared dev boxes, shell-as-a-service, jump hosts, build servers, anywhere multiple users share a kernel. Any user becomes root. |
| High | Kubernetes / container clusters | The page cache is shared across the host. A pod with the right primitives compromises the node and crosses tenant boundaries. |
| High | CI runners & build farms | GitHub Actions self-hosted runners, GitLab runners, Jenkins agents, anything that executes untrusted PR code as a regular user on a shared kernel. A pull request becomes root on the runner. |
| High | Cloud SaaS running user code | Notebook hosts, agent sandboxes, serverless functions, any tenant-supplied container or script. Tenant becomes host root. |
| Medium | Standard Linux servers | Single-tenant production where only your team has shell access. Internal LPE; chains with a web RCE or stolen credential into full server compromise. |
| Medium | WSL2 on developer workstations | Microsoft's WSL2 kernel is vulnerable until the May 12 Patch Tuesday update. A malicious npm/pip dependency that lands code in WSL becomes root inside WSL, with read/write to the user's C:\ via /mnt/c. See the WSL2 section. |
| Lower | Single-user laptops & workstations | You're already the only user. The bug doesn't grant remote attackers access by itself, but any local code execution becomes root. |
Categorization source: Theori's copy.fail "Should you patch first?" panel; WSL2 row added by the Bulletin based on the May 4 confirmation in microsoft/WSL #40365 and the practical chain through compromised npm/pip packages.
Am I affected?
Quick checks
The single highest-signal check is whether your kernel has the revert commit. On any host:
uname -r
Compare against your distribution's security advisory for the
package version that includes a664bf3d603d (or
equivalent backport).
For distro users, uname -r by itself is not a
reliable affected/patched check. A distribution may backport
the fix without changing to the upstream fixed kernel
version, or may continue to list a newer-looking vendor
kernel as vulnerable until its advisory says otherwise. Use
the per-distro advisory or package-status tracker as the
source of truth, not the upstream version number.
Specifically check:
Ubuntu · Red Hat · SUSE · Amazon Linux · Debian
To check whether the affected module is currently loaded:
lsmod | grep algif_aead
Most distros load algif_aead on demand when an
application opens an AF_ALG socket; absence from
lsmod output right now does not mean the
bug is unreachable. The kernel will auto-load the module when
requested unless you've explicitly blacklisted it (see the
mitigation step below).
Non-destructive detector (third party)
A non-destructive detector script published by an independent
researcher exercises the actual bug path against a sentinel
file in a temp directory, never touching system binaries. It
returns exit 0 if the system is patched (or
algif_aead is unreachable) and exit 2 if the
vulnerable scratch-write fires. This is a higher-signal check
than version comparison alone:
test_cve_2026_31431.py.
Read the script before running it. The same repository also
contains a working LPE; for defender purposes you only want
the detector. As with any third-party tool, run it on a host
you own or are explicitly authorized to assess.
At least one of the publicly available LPE variants targets
/etc/passwd in the page cache. Hosts running
an NSS caching daemon (nscd, sssd,
systemd-userdbd) may incidentally mask the
corrupted page from getpwnam() lookups, which
can blunt that specific exploit variant. This is
not a mitigation, the underlying primitive
is unaffected and other targets (e.g. setuid binaries in
the page cache) work regardless. But it is worth knowing
when modeling blast radius on a particular host.
Response, in priority order
-
Patch the kernel. For each affected host,
upgrade to your distribution's published kernel package that
includes the revert. Reboot, this is a kernel patch, not a
live patch by default (some vendors ship live patches; if you
use one, follow vendor guidance for activation). Verify
post-reboot with
uname -rmatching your distribution's advised patched version. -
If you can't patch immediately, blacklist
algif_aead. Per Theori's mitigation guidance, this is a defensible workaround that does not affect dm-crypt / LUKS, kTLS, IPsec / XFRM, in-kernel TLS, OpenSSL / GnuTLS / NSS default builds, SSH, or kernel keyring crypto, all of those use the in-kernel crypto API directly and don't go throughAF_ALG. The commands per copy.fail: -
Identify legitimate
AF_ALGusers on your hosts before blacklisting at scale. Userspace that explicitly usesAF_ALGis uncommon, OpenSSL with theafalgengine explicitly enabled, some embedded crypto offload paths, and applications that bindaead/skcipher/hashsockets directly are the main cases. To check before blacklisting: -
For untrusted workloads, block
AF_ALGat the seccomp layer regardless of patch state. Containers, sandboxes, CI runners, anything that executes tenant-supplied code, should deny socket creation in theAF_ALGfamily via seccomp. Do not assume the runtime default blocks this path; verify the active seccomp profile, and for untrusted workloads enforce a profile that deniesAF_ALGsocket creation explicitly. - For self-hosted CI runners specifically. If you operate self-hosted GitHub Actions runners, GitLab runners, or Jenkins agents on shared kernel hosts, treat these as Tier-1 priority. A malicious pull request or scheduled job can reach the runner's user shell, run the public PoC, and root the host. Until patched: stop running external-PR jobs on shared self-hosted runners, isolate runners to single-tenant ephemeral VMs, or move the affected repos to ephemeral cloud-hosted runners (which the cloud provider patches centrally).
- For Kubernetes operators specifically. Patch the node kernel; the page cache is a property of the host kernel, so an unpatched pod on a patched node is safe, and a patched pod on an unpatched node is not. Drain and patch nodes in normal rolling fashion, but treat the kernel-update-required pool as urgent rather than opportunistic.
-
Audit for post-exploitation indicators of
compromise. The exploit primitive itself is a
page-cache write that doesn't leave persistent on-disk
artifacts (the page cache is in-memory and not committed
back to the underlying file). On a system that was
compromised, the on-disk setuid binary is unchanged, but the
process that ran via the corrupted in-memory copy may have
executed any post-exploitation. Indicators worth checking on
any Tier-1-priority host that ran untrusted workloads in
recent weeks: unexpected new accounts, unexpected SSH
authorized keys for any account, unexpected setuid binaries
anywhere outside standard package paths, suspicious
cron / systemd timer entries, container runtime logs showing
unusual
AF_ALGsocket creation by tenant-supplied code. - For shared multi-tenant hosts you operate as a service to customers, communicate. If you sell managed Linux services (managed CI, notebook hosting, managed K8s, function-as-a-service, JupyterHub), publish a brief operator note: which kernel versions you run, when patched kernels are deployed, what mitigation is in place in the interim. Customers running tenant code on your platform need this to do their own risk reviews.
This is Theori's "Lower" priority tier on bare-metal Linux installs. The bug doesn't help a remote attacker reach your laptop on its own; you're already the only user. The risk profile is post-exploitation step-up: if a piece of malware or browser-exploit landed code execution as your unprivileged user, Copy Fail turns that into root. Apply the kernel update from your distribution on the normal cycle. No need to scramble.
If you run WSL2 on Windows, this category does not apply to you, see the WSL2 section below. The supply-chain-attack chain into your dev environment changes the calculus, and the patch isn't yet in the WSL update channel.
WSL2 specifically (Windows developers, read this)
Windows Subsystem for Linux 2 ships with a Microsoft-built
Linux kernel rather than the kernel from your chosen
distribution. That kernel
(6.6.87.2-microsoft-standard-WSL2 as of WSL
2.6.3.0) is built from a Linux source tree that
includes the vulnerable algif_aead in-place path,
and the unmodified Theori PoC produces a root shell on it. The
Ubuntu-24.04, Debian, openSUSE, and other distro images
running on top of WSL2 inherit that kernel, so the choice of
distro inside WSL does not change your exposure. Microsoft has
acknowledged the issue and announced that the patched WSL2
kernel will ship via Windows Update as part of the
May 2026 Patch Tuesday rollout (May 12).
The standard "I'm the only user, so an LPE doesn't change
much" reasoning fails for WSL2 on a developer workstation in
a way it doesn't fail for a bare-metal Linux laptop. Your
WSL2 environment routinely runs npm install,
pip install, and similar package-fetching
commands, often against direct or transitive dependencies
from the supply chain. The
Bitwarden CLI,
xinference,
Checkmarx,
and
Lightning
compromises in this Bulletin's recent series each delivered
code execution as the developer's unprivileged user inside
exactly such an environment. With Copy Fail, that
unprivileged execution becomes root inside WSL2.
Root inside WSL2 is not the same as Administrator on
Windows, but it is meaningful. Per the linked Theori
repo issue, it gives the attacker read and write access to
the user's Windows home directory and read access to the
rest of C:\ via the /mnt/c mount,
which is sufficient to steal SSH keys, GPG keys, browser
profile data, cloud-CLI credentials in
%USERPROFILE%\.aws /
.azure / .config\gcloud, and to
plant additional executable payloads inside user-writable
directories. It also enables manipulation of the WSL
environment itself, persistence inside the distro image,
and tampering with developer tooling (Git config, shell
rc files, language-toolchain hooks) that runs the next
time you start a shell.
What to do, by priority
-
Check whether you're affected. From a
Windows command prompt or PowerShell:
If
uname -rreports6.6.87.2-microsoft-standard-WSL2or any earlier WSL2 kernel build, you are vulnerable. The patched kernel version will be published with Microsoft's May 12 Patch Tuesday advisory; verify against that on the day. -
Until the WSL2 kernel update lands, blacklist
algif_aeadinside each WSL distro you use. This is the same workaround as on bare-metal Linux, applied inside the WSL distro image. From a shell inside the distro: Reboot of the WSL VM is required for the modprobe blacklist to take effect on next module load. Repeat per distro if you run multiple. -
Be especially cautious about
npm install,pip install,uv,poetry, and similar package fetches inside WSL2 until patched. The Bulletin's April supply-chain series is the active threat model here: a malicious dependency that lands code execution as your WSL user can chain Copy Fail into root inside WSL, then read and write through/mnt/c. If you regularly install dependencies from arbitrary repos for evaluation or testing, do that inside an ephemeral throwaway distro (wsl --install -d Ubuntu-Throwaway --no-launchor a Dev Container) rather than your main WSL environment until the patched kernel ships. -
On May 12, run
wsl --update. Microsoft's stated delivery channel is Windows Update, with the WSL kernel package itself updateable throughwsl --update. Re-runwsl -- uname -rafterward and confirm the kernel version matches Microsoft's May Patch Tuesday advisory. Restart WSL withwsl --shutdownbefore relying on the new kernel; running distros stay on the old kernel until the WSL VM is restarted. -
Audit credentials and secrets that lived in your
Windows user profile during the exposure window if you
suspect WSL-side compromise. If you ran any
package install from an untrusted or compromised source
between the public PoC drop (April 29) and applying the
fix, the conservative posture is to rotate SSH keys, cloud
CLI credentials, and any tokens cached in
%USERPROFILE%\.config/.aws/.azure/.kube, and to review browser-profile integrity. This is not a claim you were compromised; it is ordinary diligence for the threat model.
How the bug works, at a high level
Per Theori's copy.fail summary: the issue is a logic flaw in the
authencesn path inside the kernel's
algif_aead module, the userspace front door for
authenticated-encryption-with-associated-data operations via the
AF_ALG socket family. A 2017 optimization
(commit 72548b093ee3) made the AEAD code path
operate "in-place" rather than out-of-place, allowing source and
destination scatter-gather lists to share memory pages. In
certain combinations that path, when chained with
splice(), allowed the kernel to write a controlled
4-byte value into the page-cache page backing a readable file,
including the cached image of a setuid binary such as
/usr/bin/su.
The April 1 mainline fix is a near-complete revert of the 2017
commit: "there is no benefit in operating in-place in
algif_aead since the source and destination come
from different mappings." Once the kernel always copies
out-of-place, the page-cache pages can no longer end up in a
writable destination scatterlist, and the primitive is gone.
Theori's full technical writeup (linked in the sources) explains the chain in detail, including the exact field interactions that let the in-place handling be steered toward a page-cache target. I am deliberately not reproducing that level of detail here: the public PoC is already a complete weaponization, and a response guide doesn't need to recapitulate the chain to be useful.
What Copy Fail says about the rest of the Bulletin's recent set
The connection to the rest of this Bulletin's April series is direct. The Checkmarx, Bitwarden CLI, and xinference compromises were all about getting code execution as a regular user inside someone's CI/CD or developer environment. Until today, the next step from "attacker has user-level code execution on a CI runner" to "attacker has root on the runner host" still required a separate privilege-escalation primitive. Copy Fail is that primitive, broadly applicable across mainstream Linux kernels built between the 2017 change and the patch per Theori's reporting, with a 732-byte public PoC.
The right reading isn't "now the supply-chain attackers have a kernel exploit." It is: shared CI/CD kernels were already a concentration of risk; this disclosure makes that concentration legible, and the mitigation is the same one that was already correct, namely, don't run untrusted-code workloads on shared kernels with persistent state. Ephemeral single-tenant VMs per job, properly seccomp-restricted sandboxes, and prompt kernel patching are all on that path.
One additional note worth flagging in light of the
GitHub RCE bulletin
from yesterday: Copy Fail was found by Theori's Xint Code
tooling in roughly an hour of scan time against the kernel
crypto/ subsystem. CVE-2026-3854 was found by Wiz
using AI-augmented reverse engineering of GitHub's compiled
internal services. Two high-impact disclosures in two days,
both from teams using AI-augmented code analysis, both targeting
attack surfaces that have been audited many times before. The
cost of finding latent bugs in well-audited code is dropping
visibly. Patch posture matters more than it did six months ago,
not less.
Patch the kernel now on any multi-tenant
Linux host, Kubernetes node, self-hosted CI runner, or
cloud-SaaS-running-user-code service. Until patched, blacklist
the algif_aead module
(echo "install algif_aead /bin/false" >
/etc/modprobe.d/disable-algif.conf then
rmmod algif_aead). For untrusted workloads,
block AF_ALG via seccomp regardless of patch
state. WSL2 users: blacklist
algif_aead inside each distro now and run
wsl --update on May 12 once Microsoft ships the
patched kernel; treat npm install /
pip install from untrusted sources as a credential
exposure path through /mnt/c until then. CISA
federal patch deadline: May 15. Single-user bare-metal
laptops can patch on the normal security-update cycle.