Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-31431_CopyFail_LinuxKernel_LPE — Educational rewrite of the Copy Fail PoC (CVE-2026-31431) — Linux kernel LPE via algif_aead in-place crypto + splice() page-cache write | Kitploit
Tools/GitHubGitHub/xn0kkx/cve-2026-31431_copyfail_linuxkernel_lpe
Privilege EscalationExploit FrameworksVulnerability AnalysisExploitationLearning & EducationBinary Exploitation
GitHubxn0kkx/cve-2026-31431_copyfail_linuxkernel_lpe

CVE-2026-31431_CopyFail_LinuxKernel_LPE

Educational rewrite of the Copy Fail PoC (CVE-2026-31431) — Linux kernel LPE via algif_aead in-place crypto + splice() page-cache write

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share
View Repository
23 months agoNot yet reviewed

CVE-2026-31431 — Copy Fail (Linux Kernel LPE)

Educational rewrite of the Theori/Xint proof-of-concept for CVE-2026-31431, a local privilege escalation vulnerability in the Linux kernel's algif_aead crypto socket interface. Affects every mainline kernel from 4.14 (July 2017) through 6.18.21, and the 6.19 stable branch through 6.19.11.


Disclaimer

For educational and authorized security research only. Do NOT run on systems you do not own or do not have explicit written permission to test. Running this on a vulnerable host gives any unprivileged local user immediate root access. The authors take no responsibility for misuse.


Vulnerability Summary

The Linux kernel has exposed an in-kernel cryptography API to userspace since kernel 3.2 via the AF_ALG socket family (<linux/if_alg.h>). Userspace opens a SOCK_SEQPACKET socket, binds it to an algorithm template (e.g. "aead" / "authencesn(hmac(sha256),cbc(aes))"), and sends data for encryption or decryption.

In 2017, a performance optimisation was merged that allows AEAD algorithms to encrypt or decrypt data in-place when the kernel detects that the source and destination share the same underlying pages. This avoids a redundant memory copy on each operation.

The authencesn template (which adds Extended Sequence Number support to authenticated encryption) contains a scratch-write during decryption: it writes ESN bytes into a specific offset within the operation's data buffer before the authentication check runs. When the operation's source pages were obtained from the page cache of a regular file via splice(), and the in-place optimisation is active, this scratch write goes directly back into those cached pages.

Because the kernel's page cache is a shared mapping — any process that opens the same file sees the same physical pages — an unprivileged user can:

  1. Open any readable file (e.g. /usr/bin/su) with O_RDONLY.
  2. Splice its pages into an AF_ALG operation socket.
  3. Trigger an authencesn decryption; the ESN scratch write corrupts the page at a controlled offset with attacker-controlled bytes.
  4. The disk is never modified; only the in-memory page cache is patched.

Off-host integrity scanners (AIDE, Tripwire, IMA/EVM) that compare checksums of on-disk files are completely blind to this attack. The write vanishes after a page-cache eviction or reboot, leaving no forensic trace on disk.

By targeting /usr/bin/su (a setuid root binary) and overwriting a branch that guards the PAM authentication check, the attacker obtains a passwordless root shell.


Affected Kernels

The optimisation commit that introduced the bug landed in the 4.14 development cycle (July 2017). Any kernel compiled with CONFIG_CRYPTO_USER_API_AEAD=y and CONFIG_CRYPTO_AUTHENC=y (both common defaults) in the above ranges is vulnerable.


Affected Distributions (Non-Exhaustive)

Check your distribution's security tracker for the exact advisory status.


Requirements

  • Linux kernel in a vulnerable range (see table above)
  • Python 3.10+ (os.splice was added in Python 3.10)
  • Read access to the target binary (default: /usr/bin/su, world-readable as it is setuid)
  • No special privileges required — this is a local privilege escalation

Usage

root@kitploit:~
# Show what would be written without touching the kernel (safe):
python3 copy_fail_exploit.py --dry-run

# Patch /usr/bin/su page cache (vulnerable kernel required):
# WARNING: vulnerable kernel required -- use only on systems you own
python3 copy_fail_exploit.py

# Patch and immediately escalate to root:
python3 copy_fail_exploit.py --spawn-shell

# Use a custom target binary and payload:
python3 copy_fail_exploit.py --target /usr/bin/sudo --payload-file ./custom_patch.bin

# Verbose output (print each 4-byte write):
python3 copy_fail_exploit.py --verbose --dry-run

By default --spawn-shell is off. After patching, the script prints:

root@kitploit:~
[+] Patch applied to page cache of '/usr/bin/su' (disk unchanged).
    Run `su` to escalate, or re-run with --spawn-shell.
    To restore: echo 3 | sudo tee /proc/sys/vm/drop_caches

You must opt in to the shell spawn with --spawn-shell. This is intentional: it forces you to understand what the exploit did before executing the result.


How It Works

Setting up the primitive. The exploit opens an AF_ALG socket and binds it to the authencesn(hmac(sha256),cbc(aes)) template with a dummy all-zero key. It then configures the authentication tag size to 4 bytes via ALG_SET_AEAD_AUTHSIZE. accept() on the control socket yields an operation socket that can submit individual decrypt requests.

Triggering the page-cache write. For each 4-byte chunk of the patch payload, the exploit calls sendmsg() on the operation socket with MSG_MORE set, passing 8 bytes of associated data (AAD): 4 bytes of filler followed by the 4 payload bytes. MSG_MORE tells the kernel to hold the operation until more data arrives. It then creates a pipe and issues two splice() calls — file_fd → pipe → op_sock — donating the file's own page-cache pages as the input to the decryption operation. When recv() is finally called, the kernel runs authencesn decryption. The in-place optimisation fires (source and destination are the same pages), and the ESN scratch write copies our payload bytes into the cache page at the target offset. recv() returns EBADMSG because the authentication tag cannot verify — that is expected and harmless. The write has already happened.

Patching the binary. The embedded payload (taken verbatim from the Theori PoC) overwrites a branch instruction in /usr/bin/su from a stock util-linux build, turning a conditional jump that enforces PAM authentication into an unconditional fall-through. After patching, running su without a password succeeds and drops a root shell. The on-disk binary is untouched; dropping page-cache entries (echo 3 > /proc/sys/vm/drop_caches) reverts the change instantly.

For deeper technical analysis see the references below, in particular the Xint blog post and the Theori PoC repository.


Detection

Falco rule

root@kitploit:~
- rule: AF_ALG socket opened by unprivileged process
  desc: >
    CVE-2026-31431 — an unprivileged process opened an AF_ALG (family 38)
    socket, which is the first step of the Copy Fail exploit.
  condition: >
    evt.type = socket and
    evt.arg.domain = 38 and
    not user.uid = 0
  output: >
    AF_ALG socket opened (user=%user.name uid=%user.uid
    pid=%proc.pid comm=%proc.name)
  priority: WARNING
  tags: [host, network, privilege_escalation, CVE-2026-31431]

YARA (memory scan for the exploit script)

root@kitploit:~
rule CopyFail_CVE_2026_31431 {
    meta:
        description = "Detects Copy Fail exploit script in memory or on disk"
        cve         = "CVE-2026-31431"
    strings:
        $template = "authencesn(hmac(sha256),cbc(aes))" ascii
        $splice   = "os.splice" ascii
        $aflag    = "AF_ALG" ascii
    condition:
        all of them
}

auditd — detect AF_ALG socket creation

Add to /etc/audit/rules.d/cve-2026-31431.rules:

root@kitploit:~
-a always,exit -F arch=b64 -S socket -F a0=38 -k cve_2026_31431_afalg

Then watch logs with:

root@kitploit:~
ausearch -k cve_2026_31431_afalg --interpret

Mitigation

1. Apply the kernel patch (recommended) Upgrade to kernel 6.18.22, 6.19.12, 7.0-rc7 or later, or apply your distribution's security update.

2. Disable CONFIG_CRYPTO_USER_API_AEAD at build time If you build your own kernel, set:

root@kitploit:~
# CONFIG_CRYPTO_USER_API_AEAD is not set

This removes the entire AF_ALG AEAD interface and eliminates the attack surface. Most embedded/hardened deployments do not need it.

3. seccomp — deny AF_ALG socket family Add a seccomp filter to sensitive processes (or system-wide via a LSM policy) that rejects socket(AF_ALG, ...):

root@kitploit:~
// Deny socket() when domain == AF_ALG (38)
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 38, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | EACCES),

4. Drop page-cache privileges via kernel hardening vm.unprivileged_userfaultfd=0 and similar tunables reduce the attack surface of user-accessible kernel memory interfaces, though they do not directly block this CVE.


Cleanup After Testing

The exploit modifies only the in-memory page cache; the on-disk binary is never touched. To restore the original file content in memory, drop the kernel's page cache:

root@kitploit:~
echo 3 | sudo tee /proc/sys/vm/drop_caches

This evicts all clean pages from the cache. The next read of /usr/bin/su (or whichever binary was patched) will reload the original bytes from disk.

Rebooting also clears the page cache completely.


References

  • Original PoC — Theori
  • Technical writeup — Xint
  • Sysdig threat analysis
  • Microsoft Security Blog
  • NVD entry
  • Debian security tracker

Credits

  • Original discovery and disclosure: Theori (theori.io) and Xint (xint.io)
  • Educational rewrite: n0kk

License

MIT — see LICENSE.

MIT was chosen over a custom "educational use only" license because no such license exists as a recognized OSI/SPDX identifier. MIT is permissive, legally well-understood, and compatible with responsible disclosure repositories. The educational intent is expressed in the module docstring, this README's Disclaimer section, and the --help output — not in a legally dubious custom license clause.

Download Tool
BranchFirst VulnerableLast VulnerableFixed In
mainline4.146.18.216.18.22
6.19 stable6.19.06.19.116.19.12
7.0-rc7.0-rc17.0-rc67.0-rc7
DistributionShipped Kernel (approx.)Patched?
Debian 12 (Bookworm)6.1.xYes (backport)
Debian 13 (Trixie)6.12.x / 6.14.xYes (backport)
Ubuntu 24.04 LTS6.8.xYes (USN-7xxx)
Ubuntu 24.106.11.xYes
RHEL 9.x5.14.x (rebased)Yes (RHSA)
Alpine 3.206.6.xYes (backport)
Arch Linuxrolling (≥ 6.18.22 now)Yes
Kali Linux 2026.16.18.12Vulnerable
Kali Linux 2026.2+6.18.22+Fixed
Linux Mint 226.8.x (Ubuntu base)Yes (Ubuntu USN)