
Executive Summary
CVE-2026-43503, nicknamed DirtyClone, is a high-severity (CVSS 8.8) local privilege escalation in the Linux kernel. It is the latest survivor of the DirtyFrag vulnerability family, in which the networking stack fails to keep three distinct memory roles separate: file-backed page cache, zero-copy networking buffers, and in-place cryptographic transformations. By abusing that overlap, an unprivileged local user who holds CAP_NET_ADMIN (readily obtained inside an unprivileged user namespace) can turn IPsec decryption into a controlled write into the page cache — modifying a privileged executable such as /usr/bin/su entirely in memory.
The attack is stealthy: it leaves the on-disk binary untouched, produces no kernel logs or audit traces, and slips past on-disk integrity monitoring. JFrog’s research traces the bug to improper propagation of the SKBFL_SHARED_FRAG flag when a socket buffer (skb) is cloned via __pskb_copy_fclone() — the clone loses the flag that would otherwise force a safe copy-on-write before in-place decryption. This article walks through the DirtyFrag family, the high-level exploitation model, the specific DirtyClone primitive, the upstream fixes, and a working proof of concept.
Impact
CVE-2026-43503 is a high-severity (8.8 CVSS) local privilege escalation. It lets an unprivileged local user reach root by manipulating the page cache. Because the manipulation happens in RAM through the networking stack, the attack runs silently — it generates no kernel log entries or audit traces and bypasses tools that watch on-disk file integrity.
Affected Systems and Scope
The flaw affects modern Linux distributions where unprivileged user namespaces are enabled — including Debian, Ubuntu and Fedora. Vulnerable kernels are any that lack the complete DirtyFrag fix chain (CVE-2026-43284, CVE-2026-43500, CVE-2026-46300 and finally CVE-2026-43503). Exploitation requires the CAP_NET_ADMIN capability, which puts multi-tenant cloud environments, Kubernetes clusters and containerized workloads at the highest risk, since those routinely grant network capabilities inside namespaces.
Staying Safe (Mitigation)
The immediate recommendation is to update the Linux kernel to the fixed version (v7.1-rc5) or apply the backported patch. Where patching is not yet possible, two workarounds reduce exposure: disable unprivileged user-namespace creation with kernel.unprivileged_userns_clone=0, or blacklist the esp4, esp6 and rxrpc modules so the vulnerable in-place crypto paths cannot be reached. JFrog additionally recommends sourcing software from secure registries and scanning artifacts for known vulnerabilities.
Timeline
- May 4 — The original DirtyFrag patch lands, fixing the missing
SKBFL_SHARED_FRAGflag in spliced UDP packets. - May 13 — Fragnesia (CVE-2026-46300) is disclosed; flag loss during skb coalescing is identified.
- May 16 — An upstream multi-site patch is submitted covering the remaining frag-transfer helpers.
- May 19 — JFrog independently discovers the
__pskb_copy_fclonevariant and reports it to maintainers. - May 21 — The patch is merged (commit 48f6a5356a33).
- May 23 — CVE-2026-43503 is published.
- May 24 — Linux v7.1-rc5 is released.


DirtyFrag Vulnerability Family
DirtyFrag is a family of kernel memory-corruption flaws in how the networking stack handles socket buffers (skb) that reference shared page-cache memory, and how that memory is later mutated by in-place cryptographic transformations in the XFRM/IPsec or RxRPC subsystems. The underlying problem is that the kernel does not strictly separate three memory roles that can overlap in modern zero-copy designs:
- File-backed memory — page cache used for executables and files.
- Networking buffers — packet data processed via zero-copy paths.
- In-place transformations — e.g. encryption/decryption that writes back into the same buffer.
High-level Exploitation Model
At a high level, the attack abuses the fact that the same physical page can serve simultaneously as file data (page cache) and as network packet data (skb).
Step 1: Choose a target page
The attacker maps a privileged binary (/usr/bin/su) into the page cache and selects it as the target page to corrupt.
Step 2: Make the packet reference the page cache
A crafted IPsec packet payload is made to reference that very page-cache page using vmsplice/splice, so no copy is performed and the packet buffer and the file share the same physical memory:
int fd = open("/usr/bin/su", O_RDONLY);
char *p = mmap(NULL, mmap_size, PROT_READ, MAP_SHARED, fd, 0);
struct iovec iov = { .iov_base = p + patch_offset, .iov_len = 16 };
vmsplice(pipefd[1], &iov, 1, 0);
splice(pipefd[0], NULL, sockfd, NULL, 16, 0);
Step 3: Force local IPsec processing
A loopback-based IPsec tunnel guarantees the packet is processed locally by the same kernel instance, so the attacker controls both ends of the cryptographic exchange.
Step 4: In-place decryption becomes a write primitive
During IPsec decryption the kernel overwrites the buffer contents in place. That is normally harmless — but here the buffer is page-backed, so the write lands in the file’s page cache:
IPsec decrypt
↓
write back into skb buffer
↓
same physical page as /usr/bin/su
Step 5: Controlled overwrite of file-backed memory
The attacker controls the cryptographic inputs — key, IV and packet layout. Combined with knowledge of the original plaintext bytes, this forces a predictable decrypted output at chosen offsets inside the shared page-backed buffer, turning decryption into an arbitrary, controlled write.
Step 6: Modify the binary in memory
Using that primitive, the attacker patches instruction bytes in the cached copy of /usr/bin/su. The on-disk file is never touched — only the page cache changes:
original su page
↓
IPsec write primitive
↓
modified su page (RAM)
Step 7: Execute the modified binary
When /usr/bin/su is executed, the kernel reuses the modified cached page, runs the altered instructions, and the authentication check is bypassed — granting root:
modified page cache
↓
su executed
↓
modified logic runs
↓
root
Fixes
The original DirtyFrag fix set the SKBFL_SHARED_FRAG flag on spliced UDP packets, marking skbs that reference shared page-cache memory. That flag tells subsystems performing in-place decryption to take a safe copy-on-write path first:
shared page detected
↓
SKBFL_SHARED_FRAG = 1
↓
copy skb
↓
safe decrypt
The Fragnesia and CVE-2026-43503 fixes extend this by ensuring the flag is propagated across the various skb helpers, so it can no longer be accidentally dropped during cloning or coalescing.
Exploiting DirtyClone
Exploitation requires the CAP_NET_ADMIN capability, which an unprivileged user can typically obtain inside a new user namespace:
unshare -Urn
Step 1: Initialize a local IPsec processing environment
Inside the new network namespace, bring up the loopback interface and assign an address:
ip link set lo up
ip addr add 10.99.0.2/24 dev lo
Then establish an XFRM/IPsec state and policy for transport-mode ESP between the two 127.0.0.1 endpoints:
ip xfrm state add \
src 127.0.0.1 dst 127.0.0.1 \
proto esp spi 0x12345678 reqid 1 mode transport \
enc 'cbc(aes)' ... \
auth 'hmac(sha1)' ...
ip xfrm policy add \
src 127.0.0.1 dst 127.0.0.1 dir out \
tmpl src 127.0.0.1 dst 127.0.0.1 proto esp reqid 1 mode transport
Finally, add a netfilter TEE rule that duplicates outgoing UDP packets to 10.99.0.2, forcing the vulnerable __pskb_copy_fclone() cloning path:
iptables -t mangle -A OUTPUT -p udp --dport 4500 \
-j TEE --gateway 10.99.0.2
Key point
The TEE target is critical: it duplicates outgoing packets inside the kernel. Internally this triggers nf_dup_ipv4, which leads to skb cloning via __pskb_copy_fclone() — the exact path that loses the shared-frag flag.
Step 2: Understand the vulnerable clone behavior
When a UDP packet carrying a page-cache-backed payload is sent, the TEE rule duplicates it and the kernel calls __pskb_copy_fclone() to create a cloned skb. The crucial defect: the cloned skb does not preserve the SKBFL_SHARED_FRAG flag, while the original still carries it. That divergence is what enables the copy-on-write bypass.

Step 3: Build the IPsec routing path
Both skb instances are routed through the loopback IPsec configuration so they are processed locally. The cloned skb reaches esp_input() with a payload that still references page-cache-backed memory (the file mapping, e.g. /usr/bin/su) — the same physical page, with no copy made:
esp_input()
File-backed page (page cache)
├─ /usr/bin/su content
└─ skb payload reference
Step 4: IPsec in-place decryption path
esp_input() performs in-place decryption: the decrypted bytes overwrite the skb buffer, and because the cloned skb references page-cache memory, that write goes straight into the file-backed page:
encrypted skb payload
↓
IPsec decrypt (in place)
↓
write output into same buffer

Step 5: Controlled write via cryptographic parameters
The attacker controls the AES-CBC key material (via the SA configuration), the per-packet IV, and the packet layout/offsets. In AES-CBC each decrypted block depends on the IV, so the attacker can compute an IV that makes the decrypted output exactly what they want — turning decryption into a precise, controlled write over page-cache memory.

Step 6: Modify /usr/bin/su in memory
With a controlled write, the attacker patches selected instruction bytes inside /usr/bin/su — targeting the authentication checks and conditional branch instructions. Only small, localized changes are needed. The disk file stays unchanged while the page cache now holds modified executable code:
original su page
↓
controlled IPsec write
↓
modified su page in RAM
Step 7: Execute the modified binary
Executing /usr/bin/su loads the binary from the page cache. As long as the modified page is still cached, no disk reload happens; the modified instructions execute directly and privilege escalation is achieved:
modified page cache
↓
su executed
↓
modified logic runs
↓
privilege escalation
Proof of Concept
The JFrog team published a video demonstrating the full chain — from an unprivileged shell to root via the in-memory patch of /usr/bin/su:
Key Takeaways
- DirtyClone (CVE-2026-43503) is the latest variant of the DirtyFrag family — a missing
SKBFL_SHARED_FRAGflag lets in-place IPsec decryption write into file-backed page cache. - The defect is in skb cloning via
__pskb_copy_fclone(): the clone drops the shared-frag flag that should force copy-on-write before decryption. - A netfilter
TEErule (throughnf_dup_ipv4) is the trigger that forces the vulnerable cloning path on duplicated UDP packets. - Because the attacker controls the AES-CBC key, IV and layout, decryption becomes a precise controlled write over chosen page-cache offsets.
- Patching
/usr/bin/suin cache — not on disk — yields root with no disk changes, no kernel logs, and no audit trail, defeating file-integrity monitoring. CAP_NET_ADMINvia unprivileged user namespaces is the enabling privilege, making containerized and multi-tenant hosts the prime targets.
Defensive Recommendations
- Update to a kernel that contains the full DirtyFrag fix chain (Linux v7.1-rc5 or a backport of commit 48f6a5356a33) as the primary remediation.
- Where patching lags, disable unprivileged user namespaces with
sysctl kernel.unprivileged_userns_clone=0(or the distro equivalent). - Blacklist the
esp4,esp6andrxrpcmodules if IPsec/RxRPC is not required, removing the in-place crypto sinks. - Drop
CAP_NET_ADMINfrom container and workload security profiles unless strictly needed; audit KubernetessecurityContextand seccomp/AppArmor policies. - In multi-tenant clusters, prefer user-namespace remapping and restrict
unshare/namespace creation for untrusted workloads. - Do not rely solely on on-disk integrity monitoring — this class of attack never touches disk; add runtime/behavioral detection.
- Source software from trusted, scanned registries and keep base images current so kernel and userland fixes propagate quickly.
Conclusion
DirtyClone shows how a single dropped flag during skb cloning can re-open an entire vulnerability family. The root cause is architectural — the kernel allows one physical page to act as file cache, network buffer, and in-place crypto target at once — so each incremental fix that only plugs one helper leaves room for the next variant. The robust answer is to propagate the shared-frag marking everywhere a buffer can be cloned or coalesced, and to treat page-cache-backed network buffers as copy-on-write before any in-place transformation. Until kernels carry the complete fix chain, defenders should remove the enabling primitives (unprivileged user namespaces and unnecessary CAP_NET_ADMIN) and add runtime detection that does not depend on disk changes.
References
- JFrog Security Research — original DirtyClone write-up
- Upstream netdev patch discussion (lore.kernel.org)
- Fix commit (git.kernel.org)
Original text: “Dissecting and Exploiting Linux LPE Variant: DirtyClone (CVE-2026-43503)” by Eddy Tsalolikhin and Or Peles at JFrog Security Research.

