Dirty Frag: How a Linux Kernel Embargo Failed in Public View
On 7 May 2026, Hyunwoo Kim (@v4bel) published the Dirty Frag write-up and a working chained PoC. Two CVE IDs were live, no distribution had a patched kernel ready, and any unprivileged shell on most Linux servers was a few seconds away from root.
The bug itself is well-covered by the V4bel write-up, and we link to it everywhere it makes sense. What we want to look at instead is how the embargo around it fell apart, because that part will repeat on the next kernel zero-day.
The two CVEs:
CVE-2026-43284: thexfrm-ESP(esp4/esp6) page-cache writeCVE-2026-43500: theRxRPCpage-cache write
If you only need the workaround, the mitigation script is in Section 5.
1. Disclosure timeline
Reconstructed from V4bel's published write-up and the public netdev / lore.kernel.org archives.
| Date (UTC) | Event |
|---|---|
| 2026-04-29 | RxRPC vulnerability and exploit reported to [email protected]. RxRPC patch posted to netdev (publicly visible). |
| 2026-04-30 | xfrm-ESP vulnerability and exploit reported to [email protected]. ESP v1 patch posted to netdev (publicly visible). |
| 2026-04-30 (+9 h) | Kuan-Ting Chen independently reports the ESP vulnerability with a reproducer to [email protected]. |
| 2026-05-04 | Kuan-Ting Chen posts the shared-frag follow-up patch (the approach that eventually ships) to netdev. |
| 2026-05-07 | Shared-frag patch merged into the netdev tree. |
| 2026-05-07 | Reporter notifies [email protected] under a short embargo, with a pre-agreed fallback: a third-party leak triggers full public disclosure. |
| 2026-05-07 | Unrelated third party publishes the ESP exploit publicly, breaking the embargo. |
| 2026-05-07 | After agreement from distribution maintainers, the full Dirty Frag write-up and chained PoC are released. |
| 2026-05-08 | Mainline merge of f4c50a4034e6 (xfrm-ESP fix). |
| 2026-05-08 | CVE-2026-43284 assigned (xfrm-ESP). CVE-2026-43500 reserved (RxRPC; still no upstream patch). |
The dates that matter: the patches and the descriptions of the bugs hit the public netdev mailing list on 29 and 30 April, but linux-distros was not warned until 7 May. Seven days in public before any distribution got the heads-up.
2. Why the embargo broke
The reporter ran the disclosure by the book: report to [email protected], post the patch to netdev for review, wait for it to merge, then notify linux-distros under a short embargo. The problem is the second step. Linux has a private coordination list at [email protected], but no fix can land in git without going through public subsystem review, so the patch and the commit message hit a public list (netdev here) before linux-distros is notified. A security commit message has to describe enough of the bug for maintainers to confirm the fix is correct, which tells anyone reading the list what the bug is.
In Dirty Frag's case, the netdev archive named esp_input, esp6_input, and rxkad_verify_packet_1 and described a missing copy-on-write path on non-linear sk_buffs. Anyone who follows kernel security work could narrow the primitive down in hours, and at least one person did. On 7 May, the same day the embargo went live, an unrelated third party published a working ESP exploit. The reporter had pre-agreed with maintainers that this exact case would trigger immediate full disclosure, on the basis that defenders are better off with one authoritative write-up than with secondhand summaries chasing a leaked PoC. That clause kicked in, and the full document plus the chained PoC went public the same day.
The embargo, looking back, was never really protecting the secret. The secret was legible to anyone reading mailing lists. What the embargo was protecting was the original reporter's PoC code from being mirrored and weaponised before vendors could ship. Once a third party published a reconstruction of their own, there was nothing left to protect, and full disclosure was the less bad of two bad options.
3. What defenders face today
The CVE IDs went live with a public, working PoC and no patch on most distributions. AlmaLinux had updated kernels out the same day. Ubuntu, RHEL, SUSE, Debian, Oracle, and Rocky are still rolling. CVE-2026-43500 (RxRPC) has no upstream fix at all as of publication.
In risk terms, any unprivileged shell on a default Linux server is close to root, the exploit is deterministic, and the kernel does not panic on failure. The usual ways defenders catch this kind of activity do not work. The exploit writes to the page cache rather than through open(O_WRONLY), so file-integrity monitoring on /etc/passwd and /usr/bin/su does not see the change. There is no race window to lose, so timing heuristics do not help. Hosts that blacklisted algif_aead for Copy Fail (CVE-2026-31431) are still fully exposed, because Dirty Frag uses a different sink. And the attack does not need internet exposure, only an existing foothold on the host.
The kernels listed as confirmed-vulnerable in the published PoC, verbatim:
- Ubuntu 24.04.4:
6.17.0-23-generic - RHEL 10.1:
6.12.0-124.49.1.el10_1.x86_64 - openSUSE Tumbleweed:
7.0.2-1-default - CentOS Stream 10:
6.12.0-224.el10.x86_64 - AlmaLinux 10:
6.12.0-124.52.3.el10_1.x86_64 - Fedora 44:
6.19.14-300.fc44.x86_64
Treat the list as illustrative. The vulnerable code dates back to 17 January 2017 for xfrm-ESP and 7 June 2023 for RxRPC, so most general-purpose Linux kernels in those windows are in scope as long as they load esp4/esp6 (and, for the second variant, rxrpc). One caveat on the distro list: RHEL 10.1's default kernel package does not ship rxrpc.ko, so a default RHEL 10.1 host is exposed to the ESP variant only, not the chained PoC.
4. The bug, briefly
For root cause and the full exploit walkthrough, read the V4bel write-up. The short version:
splice() (or sendmsg(MSG_SPLICE_PAGES)) lets an unprivileged process plant a reference to a read-only page cache page, like /etc/passwd or /usr/bin/su, into the frag slot of a sender-side sk_buff. The receive-side kernel then runs an in-place crypto operation on top of that frag, which writes to the page cache page. The page cache copy of the file is modified in RAM, and every subsequent read() of the file sees the new contents.
Two paths reach this sink. xfrm-ESP gives a 4-byte arbitrary write per trigger but needs CAP_NET_ADMIN, which means a user namespace. RxRPC gives an 8-byte pcbc(fcrypt)-derived write per trigger and needs no namespace. The public exploit chains them: ESP first, RxRPC as fallback when AppArmor blocks unshare(CLONE_NEWUSER) (the default on Ubuntu 24.04+).
| Path | Introduced | Fixed (mainline) |
|---|---|---|
xfrm-ESP page-cache write |
cac2661c53f3 (2017-01-17) |
f4c50a4034e6 |
RxRPC page-cache write |
2dc334f1a63a (2023-06-07) |
Not yet merged |
5. Mitigation
Adapted from the CloudLinux KernelCare advisory. Apply this until you can install a patched kernel (or a KernelCare-style livepatch).
Blacklist esp4, esp6, and rxrpc, and unload them if they are already loaded:
sudo sh -c "printf 'install esp4 /bin/false\ninstall esp6 /bin/false\ninstall rxrpc /bin/false\n' > /etc/modprobe.d/dirtyfrag.conf; rmmod esp4 esp6 rxrpc 2>/dev/null; true"
To revert once a patched kernel is in place:
sudo rm /etc/modprobe.d/dirtyfrag.conf
esp4 and esp6 are the kernel-side ESP transforms used by IPsec, so unloading them breaks IPsec tunnels that rely on the kernel data path. Do not run this on hosts that terminate or transit IPsec, strongSwan, or Libreswan. rxrpc is the AF_RXRPC transport used almost exclusively by AFS clients and is not present on typical web-hosting servers.
The exploit modifies binaries in the page cache as part of the chain. Blacklisting alone does not undo a previous compromise, so after mitigating, drop the page cache:
sudo sh -c 'echo 3 > /proc/sys/vm/drop_caches'
6. What we took from this
A few things we are using internally as a result of the Dirty Frag disclosure.
The first is that we watch upstream kernel review lists alongside CVE feeds. The netdev archive named the vulnerable functions a week before any distribution was warned, and that pre-CVE window is not unusual for kernel security fixes. A CVE feed alone gives you a strictly worse view than a kernel maintainer has.
The second is that we keep a tested module-blacklist and sysctl playbook for the cases where there is a public PoC and no patch yet. Dirty Frag is the latest example of that pattern, and Dirty Pipe and the early days of log4shell were others. Working out which modules you can safely disable on which hosts, and what breaks when you do, is something to do in staging before the next one, not during it.
The third is about embargo policy. When a PoC for an embargoed bug shows up before vendors can ship, the embargo is doing the wrong job, and Dirty Frag's pre-agreed clause to release the authoritative write-up on third-party leak is the cleaner outcome than letting partial reconstructions circulate. If your own incident-response process treats embargoes as inviolable even after the secret is publicly out, you will lose the information advantage to attackers reading the same threads as everyone else.
The fourth, and the one we already see teams getting wrong, is that old module blacklists do not stack into coverage for new bug classes. The algif_aead blacklist that closed Copy Fail did not close Dirty Frag, and we have already seen hosts running with that mitigation in place treated as if they were covered. We now record each blacklist against the specific CVE it was applied for, not against a general label like "page-cache-write mitigation."
References
Primary sources
- V4bel/dirtyfrag (README and PoC source), Hyunwoo Kim (@v4bel)
- V4bel/dirtyfrag full technical write-up: root-cause analysis, exploit walkthrough, disclosure timeline
- AlmaLinux Security Advisory: Dirty Frag (2026-05-07): first-mover distro advisory with patched kernel-package versions
- CloudLinux KernelCare: Dirty Frag mitigation and kernel update: vendor-published mitigation script reproduced in Section 5
Kernel commits
cac2661c53f3:esp4: Avoid skb_cow_data whenever possible(2017-01-17). Introduces the xfrm-ESP skip-cow path.2dc334f1a63a:splice, net: Use sendmsg(MSG_SPLICE_PAGES) rather than ->sendpage()(2023-06-07). Exposes the splice-to-frag plant pattern that the RxRPC variant uses.f4c50a4034e6: mainline fix forCVE-2026-43284(xfrm-ESP,SKBFL_SHARED_FRAGapproach).
Mailing-list patches (the public review traffic that pre-empted the embargo)
- RxRPC patch (v4bel): proposed fix for
CVE-2026-43500. Not yet merged upstream. - xfrm-ESP v1 patch (v4bel): original direct-
skb_cow_dataapproach. - xfrm-ESP shared-frag patch (Kuan-Ting Chen): final merged approach.
Bug-class background
- Dirty Pipe (
CVE-2022-0847), Max Kellermann. Originalstruct pipe_bufferpage-cache write. - Copy Fail (
CVE-2026-31431):algif_aead-based predecessor that motivated this research.
Related Reconix Services
- Penetration Testing: comprehensive testing to identify exploitable vulnerabilities and post-exploitation paths attackers would chain after initial access.
- Vulnerability Assessment: continuous scanning and patch-status validation to surface unpatched kernel exposures across your Linux fleet.
- Red Teaming: adversary emulation engagements that test whether a local-only zero-day like Dirty Frag could be reached and weaponised in your environment.
- Cybersecurity Consulting: guidance on hardening Linux baselines, kernel module attack-surface reduction, and incident response readiness for newly disclosed zero-days.