During an audit of recent Linux kernel patches, the JFrog Security Research team identified that despite fixes addressing the DirtyFrag vulnerability family, a residual issue remained unaddressed. This gap allowed the same vulnerability class to persist through a different packet processing path in the XFRM/IPsec subsystem.
We reported the issue to the Linux kernel maintainers on May 19. This coincided with a related broader report from the original DirtyFrag researcher “Hyunwoo Kim" on May 16. The variants were patched and merged into mainline on May 21 (v7.1-rc5, 9e171fc1d7d7), and assigned CVE-2026-43503.
At the time of writing, no public PoC existed for this vulnerability. JFrog researchers successfully developed a privilege escalation exploit for a newly discovered DirtyFrag variant of CVE-2026-43503, which we dubbed "DirtyClone". We are publishing this research because it demonstrates a broader exploitation pattern affecting multiple skb (socket buffer) processing paths, showing that the underlying attack primitive is not limited to a single vulnerable code path.
CVE-2026-43503 is a high-severity (8.8 CVSS) Local Privilege Escalation (LPE) flaw.
The severity of this issue is significant because it allows any unprivileged local user to gain root access (LPE) by manipulating the Linux page cache. The attack is silent, leaves no kernel logs or audit traces, and bypasses common on-disk integrity monitoring tools.
This flaw impacts a broad array of modern Linux distributions that run the necessary kernel versions and configurations.
- Vulnerable distributions: The attack is confirmed to work on popular distributions where unprivileged user namespaces are enabled, including Debian, Ubuntu, and Fedora
- Vulnerable kernels: Any kernel lacking the complete chain of fixes for the DirtyFrag vulnerability family is at risk. Systems entirely unpatched for the original flaws (CVE-2026-43284 and CVE-2026-43500) remain broadly exposed. Additionally, any mainline, stable, or Long Term Support (LTS) kernel branch that applied the initial mitigations but lacks the subsequent follow-up patches (CVE-2026-46300 and CVE-2026-43503) remains vulnerable to specific bypasses. A system is only fully protected against this exploitation model once the entire series of patches is applied..
- Who is exploitable: Any local user on a server or device running a vulnerable kernel who holds or can acquire the CAP_NET_ADMIN capability (frequently obtainable via unprivileged user namespaces). This poses the highest risk to multi-tenant cloud environments, Kubernetes clusters, and containerized workloads where user namespaces are enabled or privileged containers are deployed.
The issue was patched and merged into mainline on May 21, 2026.
- Immediate Recommendation: Users should immediately update their Linux kernel to the fixed version, v7.1-rc5, or apply the backported patch for CVE-2026-43503 to their distribution's kernel.
- Workarounds: If immediate patching is not possible, workarounds include blocking CAP_NET_ADMIN acquisition by setting kernel.unprivileged_userns_clone=0 or blacklisting esp4, esp6, and rxrpc kernel modules block the in-place decryption primitives..
- What This Means for JFrog Customers: As this vulnerability targets the host kernel, it emphasizes the need for a strong security posture. JFrog Artifactory and Xray are crucial in this defense; ensure all binaries and packages are sourced through a secure, curated registry (Artifactory, Repo21) and regularly scanned by Xray to block malicious or unapproved packages before they reach your machines, mitigating potential supply chain risks that could facilitate such a kernel LPE.

- May 4: DirtyFrag patch (CVE-2026-43284 and CVE-2026-43500) lands in Linux kernel mainline. It fixes a bug where the SKBFL_SHARED_FRAG flag was missing from spliced UDP packets, ensuring subsystems performing in-place decryption trigger a safe Copy-on-Write.
- May 13: Fragnesia (CVE-2026-46300) disclosed; patch lands in Linux kernel netdev. Flag lost during skb coalescing (skb_try_coalesce), bypassing the mitigation.
- May 16: Upstream multi-site patch submitted, covering the remaining frag-transfer helpers (__pskb_copy_fclone, skb_shift, skb_segment, skb_gro_receive, skb_gro_receive_list, tcp_clone_payload).
- May 19: JFrog independently rediscovers the in __pskb_copy_fclone variant, builds a PoC, and reports it.
- May 21: Patch merged to mainline (commit 48f6a5356a33).
- May 23: CVE-2026-43503 published.
- May 24: Linux v7.1-rc5 released, first fixed tag.

DirtyFrag is a family of Linux kernel memory corruption vulnerabilities in the core networking stack affecting how socket buffers (skb) reference shared page-cache memory, which are subsequently weaponized through in-place cryptographic transformations in subsystems like XFRM/IPsec or RxRPC.
Despite targeting different packet cloning or forwarding paths, variants like DirtyFrag, Fragnesia, and DirtyClone all rely on a shared technique: tricking the kernel into treating read-only, file-backed page cache memory as writable network buffers.
At a high level, the kernel does not strictly separate three memory roles that can overlap in modern 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 writing back into the same buffer)
When these three contexts intersect, the kernel may modify memory that is still semantically tied to a file, leading to corruption of file-backed data in place.
The attack abuses a situation where the same physical memory page is used both as:
- File data (page cache)
- Network packet data (skb)
Normally, these are separate:
- File → page cache page
- Network → skb buffer
DirtyFrag connects them.
To exploit this overlap, the attacker follows these steps:
The attacker maps a privileged binary such as /usr/bin/su, causing it to be loaded into the page cache.
/usr/bin/su
↓
Page-cache page (RAM)
This page becomes the target for manipulation.
The attacker crafts an IPsec packet whose payload is backed by the same page-cache page.
Using vmsplice and splice, the kernel attaches page-cache-backed memory into an skb instead of copying it.
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);
At this point, the packet buffer is literally backed by file memory.
The attacker uses a loopback-based IPsec tunnel so that packets remain local.
This ensures:
- The packet is created by the attacker
- The same kernel processes the packet
- The packet passes through the IPsec receive path
When processed, the packet reaches the ESP decryption stage (esp_input()).
IPsec decrypts packet payloads in place for performance.
That means:
- input buffer \= output buffer
- Decrypted bytes overwrite the same memory
Normally safe, but here the buffer is backed by a page cache page.
If the skb data resides in a page-backed buffer originating from a file mapping, in-place decryption can modify that shared page content.
IPsec decrypt
↓
write back into skb buffer
↓
same physical page as /usr/bin/su
The attacker controls cryptographic inputs (key, IV, and packet layout).
In AES-CBC, the IV influences the first decrypted block.
By combining:
- Known original bytes
- Chosen ciphertext structure
- Controlled IV
The attacker can force predictable output bytes at specific offsets, which can, under constrained conditions, influence the resulting decrypted bytes in shared page-backed buffers.
The attacker uses this primitive to patch small instruction sequences inside /usr/bin/su.
Only a few bytes are needed (e.g., conditional branch logic controlling authentication).
The file on disk is unchanged, but the page-cache copy is modified.
original su page
↓
IPsec write primitive
↓
modified su page (RAM)
When /usr/bin/su is executed again:
- Linux reuses the cached page
- Modified instructions are used directly
- Authentication logic is bypassed
Result: privilege escalation.
modified page cache
↓
su executed
↓
modified logic runs
↓
root
The original DirtyFrag fix set the SKBFL_SHARED_FRAG for spliced UDP packets. This is a metadata flag marking skb packets that reference shared page-cache memory, ensuring subsystems performing in-place decryption trigger a safe Copy-on-Write.
If this flag is set, IPsec forces a copy before decryption.
shared page detected
↓
SKBFL_SHARED_FRAG = 1
↓
copy skb
↓
safe decrypt
This prevents direct modification of file-backed pages.
The Fragnesia and CVE-2026-43503 fixes make sure the SKBFL_SHARED_FRAG flag propagates across functions and isn’t accidentally ‘dropped’ along the way.
In order to configure the required networking and IPsec environment, CAP_NET_ADMIN is needed, as it allows control over network interfaces, routing, and XFRM/IPsec policies.
The attacker begins by creating a fresh network namespace:
unshare -Urn
This provides network administrative capabilities inside the namespace. While capabilities are namespaced, page cache is shared at the host level, so if file-backed pages are modified through shared mappings, the effects may propagate to other processes using those pages.
The attacker configures a loopback-based IPsec tunnel, so packets are processed locally by the same kernel instance.
ip link set lo up
ip addr add 10.99.0.2/24 dev lo
Then an IPsec (XFRM) state is created (creating the IPsec Interface):
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)' ...
A matching policy forces outbound traffic through IPsec:
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, a netfilter rule is added (that forces our packet through the vulnerable fclone path):
iptables -t mangle -A OUTPUT -p udp --dport 4500 \
-j TEE --gateway 10.99.0.2
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()
When a UDP packet (similar to the described in High-level Exploitation Model - Step 2) is sent:
- The original skb is created.
- The TEE rule duplicates it.
- The kernel calls __pskb_copy_fclone() to create a cloned skb.
At this point, two skb objects exist:
- Original skb → follows normal path
- Cloned skb → enters vulnerable transformation path
During cloning, the cloned skb does not correctly preserve the SKBFL_SHARED_FRAG flag.
This flag is the kernel’s safety marker indicating that the skb references shared (potentially file-backed) page memory. As a result:
- Original skb = safe - metadata intact
- Cloned skb = unsafe - metadata missing
This divergence is the root of the DirtyClone bypass.

Both skb instances are routed through the local loopback-based IPsec configuration.
This ensures:
- Packets remain local
- Packets are processed by the same kernel instance
- Cloned skb reaches the IPsec receive path
Eventually, the cloned skb reaches:
esp_input()
At this point, the skb payload is not ordinary network memory. Instead, it references page-cache-backed memory originating from a file mapping (for example, /usr/bin/su).
So the memory layout is:
File-backed page (page cache)
├─ /usr/bin/su content
└─ skb payload reference
Importantly, the skb does not copy the data; it references the same physical page. This shared reference enables the page-cache write primitive reused across all DirtyFrag variants.
When the cloned skb reaches esp_input(), IPsec performs decryption on the packet payload.
For performance reasons, this is done in-place:
- input buffer \== output buffer
- Decrypted bytes overwrite existing skb memory.
Conceptually:
encrypted skb payload
↓
IPsec decrypt (in place)
↓
write output into same buffer
Because the cloned skb references page-cache memory, the kernel writes decrypted data directly into a file-backed page

The attacker does not just get arbitrary writes.
They control:
- AES-CBC key material (via SA configuration)
- IV per packet
- Packet layout and offsets
In AES-CBC:
- Each decrypted block depends on the IV
- An attacker can compute an IV such that the output becomes predictable
So by combining known original bytes, desired target bytes, and controlled IV, the attacker transforms decryption into a controlled write primitive over page-cache memory.
The packet sent looks as follows:

Using this primitive, the attacker patches selected instruction bytes inside /usr/bin/su.
Typical targets for patching include authentication checks and conditional branch instructions. Only small localized changes are required. The result is that the disk file remains unchanged, and the page cache contains modified executable code.
original su page
↓
controlled IPsec write
↓
modified su page in RAM
When /usr/bin/su is executed, Linux loads the binary from the page cache. If the modified page is still cached:
- No disk reload is required
- modified instructions are executed directly
Execution flow:
modified page cache
↓
su executed
↓
modified logic runs
↓
privilege escalation