## https://sploitus.com/exploit?id=71205293-B63B-5A59-A5EF-F5CBA3350D57
# CVE-2026-31431 "Copy Fail" โ Detection & Response Package
**Published:** 2026-04-30
**CVSSv3:** 7.8 (High)
**Type:** Local Privilege Escalation (LPE)
**Subsystem:** Linux kernel `algif_aead` / `authencesn` cryptographic template
**Affected:** Linux kernels 4.14 โ 6.18.21 (virtually all distributions since 2017)
**References:**
- [Xint/Theori Write-up](https://xint.io/blog/copy-fail-linux-distributions)
- [Official PoC](https://github.com/theori-io/copy-fail-CVE-2026-31431)
- [oss-security Disclosure](https://seclists.org/oss-sec/2026/q2/281)
- [copy.fail](https://copy.fail)
---
## Table of Contents
1. [Vulnerability Summary](#vulnerability-summary)
2. [How the Exploit Works](#how-the-exploit-works)
3. [Detection Limitations](#detection-limitations)
4. [Immediate Mitigation](#immediate-mitigation)
5. [YARA Rule](#yara-rule)
6. [Auditd Rules](#auditd-rules)
7. [Wazuh Rules](#wazuh-rules)
8. [MISP Event Template](#misp-event-template)
9. [Patching & Remediation](#patching--remediation)
10. [Key IoCs Reference](#key-iocs-reference)
---
## Vulnerability Summary
CVE-2026-31431 is a logic flaw introduced in kernel 4.14 (2017) at the intersection of three independent changes:
1. The `authencesn` template (added 2011 for IPsec ESN support) writes 4 bytes of scratch data past its output buffer boundary.
2. `AF_ALG` gained AEAD support in 2015, allowing userspace to submit data via `splice()` from page-cached files.
3. In 2017, `algif_aead.c` was optimized to operate in-place (`req->src == req->dst`), placing live page-cache pages into a writable scatterlist.
The result: an unprivileged user can write exactly 4 attacker-controlled bytes into the kernel's page-cache copy of any readable file โ including setuid binaries and `/etc/passwd` โ without touching the on-disk file. The working PoC is a 732-byte Python script. No race condition. No per-distribution offsets. Reliable across Ubuntu, RHEL, Amazon Linux, and SUSE.
---
## How the Exploit Works
```
Attacker opens AF_ALG socket (family 38, type 5)
โโ Binds to "authencesn(hmac(sha256),cbc(aes))"
โโ Sets SOL_ALG (279) options including key and authsize
โโ Accepts a connection socket
Attacker opens target file (e.g., /etc/passwd) read-only
โโ Uses splice() to feed page-cache pages into the AEAD socket's RX buffer
โโ Sends crafted AAD via sendmsg() โ bytes 4โ7 of AAD = attacker-controlled write value
authencesn performs in-place decryption:
โโ scatterwalk_map_and_copy writes seqno_lo into the chained page-cache page
โโ recvmsg() returns an error (HMAC fails โ expected), but the write already happened
Page-cache now contains attacker-modified copy of the file
โโ Kernel executes from page-cache, not disk
โโ On-disk file is UNCHANGED โ file integrity tools see nothing
```
The PoC targets `/etc/passwd`: it finds the offset of the running user's UID field and overwrites it with `0000`, then invokes `su` to obtain a root shell.
---
## Detection Limitations
> **Read this section before deploying any rules below.**
This exploit has two properties that significantly limit detection coverage:
**1. The write goes to the page cache, not the filesystem.**
Any detection tool that monitors file system events โ `inotify`, `fanotify`, AIDE, Tripwire, auditd path watches โ will **not** observe the modification. The on-disk file is never written. This means the `-p w` (write) flags in auditd path watches for `/usr/bin/su` or `/etc/passwd` will not catch the actual exploitation write.
**2. The mechanism uses legitimate kernel interfaces.**
`AF_ALG` sockets, `splice()`, and `authencesn` all have legitimate uses (IPsec, kernel self-tests, sendfile-style I/O). Detection must focus on the *combination* of these primitives rather than any one in isolation, and false positives should be expected on systems running IPsec or doing kernel crypto testing.
**What detection CAN catch:**
- The `socket(AF_ALG, SOCK_SEQPACKET, 0)` syscall
- The `splice()` syscall correlated with the above, especially near setuid binary access
- The PoC script itself (via YARA)
- The specific `authencesn(hmac(sha256),cbc(aes))` algorithm string in process memory or script files
**What detection CANNOT catch:**
- The actual page-cache write (in-memory, no filesystem event)
- Post-exploitation use of the modified page-cache entry (looks like a normal `su` or `passwd` call)
- Variants that avoid Python or the specific algorithm string
---
## Immediate Mitigation
Before deploying detection rules, apply this mitigation on any unpatched host:
```bash
# Disable algif_aead kernel module โ blocks the exploit primitive entirely
echo "install algif_aead /bin/false" | sudo tee /etc/modprobe.d/disable-algif-aead.conf
sudo rmmod algif_aead 2>/dev/null || true
```
**Verify the mitigation is active** using the official detector:
```bash
# Exit 0 = not vulnerable / mitigated
# Exit 2 = VULNERABLE
python3 test_cve_2026_31431.py
```
> **Note:** The `rmmod` command will fail if the module is not currently loaded; this is acceptable. The `modprobe.d` config prevents future loads. This mitigation has no impact on standard TLS, SSH, or filesystem encryption workloads โ it only affects IPsec with Extended Sequence Numbers using the `authencesn` template, which is uncommon outside dedicated VPN gateways.
---
## YARA Rule
Save as `cve_2026_31431.yar`
> **Scanning scope:** This rule is designed to scan Python script files on disk or pulled from memory dumps. It will match the known PoC and close variants. It will NOT detect the exploit activity at the syscall level โ use the auditd/Wazuh rules for that.
```yara
rule CVE_2026_31431_CopyFail_PoC_HighConfidence {
meta:
description = "High-confidence match: CVE-2026-31431 Copy Fail PoC or close variant"
author = "Detection Engineering"
reference = "https://xint.io/blog/copy-fail-linux-distributions"
cve = "CVE-2026-31431"
date = "2026-04-30"
severity = "High"
cvss = "7.8"
strings:
// Algorithm string unique to this exploit path โ very high fidelity
$alg_full = "authencesn(hmac(sha256),cbc(aes))" ascii
// Specific socket call signature from PoC: AF_ALG=38, SOCK_SEQPACKET=5
$socket_call = "socket(38,5,0)" ascii
// SOL_ALG socket option (decimal 279)
$solalg = "setsockopt(279" ascii
// Hex key/iv payload written via setsockopt in PoC
$key_payload = "0800010000000010" ascii
// splice() usage in context of AEAD operations
$splice = "splice(" ascii
// Target indicators from PoC (page-cache corruption targets)
$target_passwd = "/etc/passwd" ascii
$target_su = "/usr/bin/su" ascii
// AF_ALG aead bind strings
$aead_bind = "\"aead\"" ascii
condition:
// High-confidence: unique algorithm string alone is sufficient
$alg_full
or
// Medium-confidence: socket primitive + option number
($socket_call and $solalg)
or
// Medium-confidence: splice into AEAD socket targeting a setuid path
($aead_bind and $splice and ($target_passwd or $target_su))
or
// PoC hex payload present alongside splice
($key_payload and $splice)
}
rule CVE_2026_31431_CopyFail_Mechanism {
meta:
description = "Behavioral: AF_ALG AEAD + splice combination suggestive of CVE-2026-31431 technique"
author = "Detection Engineering"
reference = "https://xint.io/blog/copy-fail-linux-distributions"
cve = "CVE-2026-31431"
date = "2026-04-30"
severity = "Medium"
note = "Higher false positive rate than HighConfidence rule โ review matches in context"
strings:
$authencesn = "authencesn" ascii nocase
$af_alg_num = "socket(38" ascii
$sol_alg_num = "279" ascii
$splice = "splice(" ascii
condition:
($authencesn and $splice)
or
($af_alg_num and $sol_alg_num and $splice)
}
```
---
## Auditd Rules
Save as `/etc/audit/rules.d/cve-2026-31431.rules`
Reload with:
```bash
sudo augenrules --load
# or on older systems:
sudo auditctl -R /etc/audit/rules.d/cve-2026-31431.rules
```
```bash
## ============================================================
## CVE-2026-31431 "Copy Fail" โ Auditd Detection Rules
## ============================================================
## These rules capture the MECHANISM of the exploit (socket +
## splice syscalls) and correlated /etc/passwd access patterns.
##
## IMPORTANT: These rules will NOT detect the page-cache write
## itself โ it is an in-memory operation with no filesystem
## event. File path watches (-w) on setuid binaries or
## /etc/passwd will not fire on the exploit write.
##
## Correlate rule hits across audit.key values to build signal:
## A hit on afalg_socket followed closely by a hit on
## splice_syscall from the same process is a strong indicator.
## ============================================================
## --- Core exploit primitive: AF_ALG socket creation ---
## Monitors socket(2) syscall where a0 = 0x26 (38 decimal = AF_ALG)
## This is the first step of the exploit chain.
-a always,exit -F arch=b64 -S socket -F a0=0x26 -k cve_2026_31431_afalg_socket
-a always,exit -F arch=b32 -S socket -F a0=0x26 -k cve_2026_31431_afalg_socket
## --- splice() syscall monitoring ---
## splice() is used to feed page-cache pages into the AEAD socket.
## NOTE: splice() is commonly used for sendfile-like operations.
## Correlate with cve_2026_31431_afalg_socket hits from the same PID.
-a always,exit -F arch=b64 -S splice -k cve_2026_31431_splice
-a always,exit -F arch=b32 -S splice -k cve_2026_31431_splice
## --- /etc/passwd access monitoring ---
## The PoC reads /etc/passwd to locate the UID field offset.
## Read access (-p r) is retained here because the intent is
## to correlate this read with the AF_ALG socket key above,
## not to use the watch as a standalone alert.
-w /etc/passwd -p rwa -k cve_2026_31431_passwd_access
## --- setuid binary execution monitoring ---
## Detects execution of su after page-cache modification.
## The page-cache write makes su execute as root; this catches
## the exploitation outcome, not the write itself.
-w /usr/bin/su -p xa -k cve_2026_31431_su_exec
-w /usr/bin/sudo -p xa -k cve_2026_31431_sudo_exec
## --- algif_aead module state monitoring ---
## The exploit requires algif_aead to be loaded.
## Monitoring modprobe helps detect attempts to load the module
## on systems where it was previously disabled as a mitigation,
## and confirms whether the mitigation is being bypassed.
-a always,exit -F arch=b64 -S finit_module -S init_module -k cve_2026_31431_module_load
-w /etc/modprobe.d -p wa -k cve_2026_31431_modprobe_conf
```
### Querying for correlations
After deploying the rules, use `ausearch` to correlate hits across keys within a time window:
```bash
# Find all CVE-2026-31431 related events in the last hour
sudo ausearch -k cve_2026_31431_afalg_socket -k cve_2026_31431_splice \
--start recent -i | aureport --interpret
# Check if a specific PID hit both AF_ALG and splice
sudo ausearch -k cve_2026_31431_afalg_socket --start today -i \
| grep 'pid=' | awk -F'pid=' '{print $2}' | awk '{print $1}' | sort -u \
| while read pid; do
sudo ausearch -k cve_2026_31431_splice --start today -i | grep "pid=$pid" \
&& echo "[!] PID $pid hit both AF_ALG and splice โ investigate"
done
```
---
## Wazuh Rules
Save as a local rules file (typically `/var/ossec/etc/rules/local_rules.xml`).
> **Prerequisites:** These rules depend on auditd being configured with the rules above and the Wazuh auditd decoder being active. They match on the `audit.key` field populated by auditd, which is the correct and reliable way to bridge the two systems. The rules use `auditd` rather than a specific `` to remain compatible across Wazuh versions.
```xml
auditd
cve_2026_31431_afalg_socket
CVE-2026-31431 Copy Fail: AF_ALG socket (family 38) created by unprivileged process
cve,privilege_escalation,linux,kernel,crypto,
auditd
cve_2026_31431_splice
CVE-2026-31431 Copy Fail: splice() syscall detected โ monitor for correlation with AF_ALG socket rule
cve,privilege_escalation,linux,kernel,
112001
auditd
cve_2026_31431_splice
audit.pid
CVE-2026-31431 Copy Fail CRITICAL: AF_ALG socket creation followed by splice() from same process โ active exploitation likely
cve,privilege_escalation,linux,kernel,crypto,high_confidence,
112001
auditd
cve_2026_31431_passwd_access
CVE-2026-31431 Copy Fail: /etc/passwd access following AF_ALG socket creation โ consistent with PoC target selection
cve,privilege_escalation,linux,kernel,
112001
auditd
cve_2026_31431_su_exec|cve_2026_31431_sudo_exec
CVE-2026-31431 Copy Fail: su/sudo execution following AF_ALG socket creation โ possible post-exploitation
cve,privilege_escalation,linux,kernel,
auditd
cve_2026_31431_module_load
^.*(python|python3|insmod|modprobe).*$
CVE-2026-31431 Copy Fail: Kernel module load attempt โ verify algif_aead mitigation has not been bypassed
cve,privilege_escalation,linux,kernel,
auditd
cve_2026_31431_modprobe_conf
CVE-2026-31431 Copy Fail: /etc/modprobe.d modified โ verify algif_aead disable config has not been removed
cve,privilege_escalation,linux,kernel,
```
---
## MISP Event Template
Save as `misp_cve_2026_31431.json` and import via MISP โ Events โ Import.
> **Note:** Replace the placeholder UUIDs below with freshly generated UUID4s for your environment before import. Placeholder values are shown in a consistent format for readability.
```json
{
"Event": {
"uuid": "7f3a2d1e-8b4c-4f9a-a3e2-6d5c1b8e9f0a",
"info": "CVE-2026-31431 Copy Fail โ Linux LPE via authencesn page-cache write",
"threat_level_id": "2",
"analysis": "2",
"date": "2026-04-30",
"Attribute": [
{
"type": "vulnerability",
"category": "External analysis",
"to_ids": false,
"uuid": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
"comment": "CVE identifier",
"value": "CVE-2026-31431"
},
{
"type": "text",
"category": "Other",
"to_ids": false,
"uuid": "2b3c4d5e-6f7a-8b9c-0d1e-2f3a4b5c6d7e",
"comment": "Vulnerability description",
"value": "Logic flaw in Linux kernel authencesn cryptographic template. An unprivileged local user can write 4 attacker-controlled bytes into the page cache of any readable file via AF_ALG + splice(), enabling local privilege escalation. No race condition required. Affects kernels 4.14 through 6.18.21."
},
{
"type": "text",
"category": "Other",
"to_ids": false,
"uuid": "3c4d5e6f-7a8b-9c0d-1e2f-3a4b5c6d7e8f",
"comment": "Attack vector summary",
"value": "socket(38, 5, 0) [AF_ALG/SOCK_SEQPACKET] โ bind authencesn(hmac(sha256),cbc(aes)) โ setsockopt(SOL_ALG/279) โ splice() page-cache pages into AEAD socket โ 4-byte controlled write into page cache of target file"
},
{
"type": "text",
"category": "Other",
"to_ids": false,
"uuid": "4d5e6f7a-8b9c-0d1e-2f3a-4b5c6d7e8f9a",
"comment": "Affected kernel range",
"value": "Linux kernel 4.14 (commit 72548b093ee3) through 6.18.21"
},
{
"type": "text",
"category": "Other",
"to_ids": false,
"uuid": "5e6f7a8b-9c0d-1e2f-3a4b-5c6d7e8f9a0b",
"comment": "Introducing commit (root cause)",
"value": "72548b093ee38a6d4f2a19e6ef1948ae05c181f7 โ algif_aead in-place AEAD optimization (2017)"
},
{
"type": "text",
"category": "Other",
"to_ids": false,
"uuid": "6f7a8b9c-0d1e-2f3a-4b5c-6d7e8f9a0b1c",
"comment": "Fix commit โ kernel 6.18.22 stable",
"value": "fafe0fa2995a0f7073c1c358d7d3145bcc9aedd8"
},
{
"type": "text",
"category": "Other",
"to_ids": false,
"uuid": "7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d",
"comment": "Fix commit โ kernel 6.19.12 stable",
"value": "ce42ee423e58dffa5ec03524054c9d8bfd4f6237"
},
{
"type": "text",
"category": "Other",
"to_ids": false,
"uuid": "8b9c0d1e-2f3a-4b5c-6d7e-8f9a0b1c2d3e",
"comment": "Fix commit โ kernel 7.0 mainline",
"value": "a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5"
},
{
"type": "text",
"category": "Other",
"to_ids": true,
"uuid": "9c0d1e2f-3a4b-5c6d-7e8f-9a0b1c2d3e4f",
"comment": "IoC: Socket family (AF_ALG)",
"value": "socket family 38 (AF_ALG)"
},
{
"type": "text",
"category": "Other",
"to_ids": true,
"uuid": "0d1e2f3a-4b5c-6d7e-8f9a-0b1c2d3e4f5a",
"comment": "IoC: Socket type (SOCK_SEQPACKET)",
"value": "socket type 5 (SOCK_SEQPACKET)"
},
{
"type": "text",
"category": "Other",
"to_ids": true,
"uuid": "1e2f3a4b-5c6d-7e8f-9a0b-1c2d3e4f5a6b",
"comment": "IoC: Socket option (SOL_ALG = 279)",
"value": "setsockopt level 279 (SOL_ALG)"
},
{
"type": "text",
"category": "Other",
"to_ids": true,
"uuid": "2f3a4b5c-6d7e-8f9a-0b1c-2d3e4f5a6b7c",
"comment": "IoC: Algorithm string (highest fidelity)",
"value": "authencesn(hmac(sha256),cbc(aes))"
},
{
"type": "text",
"category": "Other",
"to_ids": true,
"uuid": "3a4b5c6d-7e8f-9a0b-1c2d-3e4f5a6b7c8d",
"comment": "IoC: Primary PoC target file",
"value": "/etc/passwd (UID field offset targeted by PoC)"
},
{
"type": "text",
"category": "Other",
"to_ids": true,
"uuid": "4b5c6d7e-8f9a-0b1c-2d3e-4f5a6b7c8d9e",
"comment": "IoC: Secondary targets (setuid binaries)",
"value": "/usr/bin/su, /usr/bin/sudo"
},
{
"type": "text",
"category": "Other",
"to_ids": false,
"uuid": "5c6d7e8f-9a0b-1c2d-3e4f-5a6b7c8d9e0f",
"comment": "Immediate mitigation",
"value": "echo 'install algif_aead /bin/false' > /etc/modprobe.d/disable-algif-aead.conf && rmmod algif_aead"
},
{
"type": "url",
"category": "External analysis",
"to_ids": false,
"uuid": "6d7e8f9a-0b1c-2d3e-4f5a-6b7c8d9e0f1a",
"comment": "Official write-up",
"value": "https://xint.io/blog/copy-fail-linux-distributions"
},
{
"type": "url",
"category": "External analysis",
"to_ids": false,
"uuid": "7e8f9a0b-1c2d-3e4f-5a6b-7c8d9e0f1a2b",
"comment": "Official PoC repository",
"value": "https://github.com/theori-io/copy-fail-CVE-2026-31431"
}
],
"Object": [
{
"name": "vulnerability",
"meta-category": "vulnerability",
"Attribute": [
{
"type": "vulnerability",
"object_relation": "id",
"value": "CVE-2026-31431"
},
{
"type": "cvss-score",
"object_relation": "cvss-score",
"value": "7.8"
},
{
"type": "text",
"object_relation": "summary",
"value": "Linux kernel authencesn LPE via AF_ALG + splice() page-cache write"
}
]
}
]
}
}
```
---
## Patching & Remediation
### Kernel Patch
| Branch | Fixed Version | Fix Commit |
|--------|--------------|------------|
| Stable 6.18.x | 6.18.22 | `fafe0fa2995a0f7073c1c358d7d3145bcc9aedd8` |
| Stable 6.19.x | 6.19.12 | `ce42ee423e58dffa5ec03524054c9d8bfd4f6237` |
| Mainline | 7.0 | `a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5` |
The fix reverts the 2017 in-place AEAD optimization in `algif_aead.c` back to out-of-place operation, ensuring page-cache pages are never placed in a writable scatterlist.
### Distribution-Specific Guidance
| Distribution | Action |
|---|---|
| Ubuntu | `apt-get update && apt-get upgrade linux-image-generic`; check for USN advisory |
| RHEL / Rocky / Alma | `dnf update kernel`; check RHSB advisory |
| Amazon Linux 2023 | `dnf update kernel`; check ALAS advisory |
| SUSE / openSUSE | `zypper update kernel-default`; check SUSE SA advisory |
| Debian | Check security tracker; backported patch may arrive before kernel update |
| Arch | `pacman -Syu` (rolling; pick up upstream fix as it lands) |
### Integrity Verification After Exposure
If you suspect exploitation occurred on a host before patching:
```bash
# 1. Check if /etc/passwd UID fields have been tampered
# (compare against a known-good backup or secondary host)
awk -F: '$3 ~ /^0+$/ && $1 != "root" {print "SUSPICIOUS UID 0 ENTRY:", $0}' /etc/passwd
# 2. Drop the page cache to flush any in-memory modifications
# WARNING: This impacts performance temporarily
sync && echo 3 | sudo tee /proc/sys/vm/drop_caches
# 3. Verify setuid binaries against package manager
rpm -Va --nomtime 2>/dev/null | grep -E '^.{0,8}5.*su$|^.{0,8}5.*sudo$' # RHEL/rpm
debsums -s 2>/dev/null | grep -E 'su|sudo' # Debian/Ubuntu
# 4. Re-examine recently logged su/sudo invocations for unexpected UID transitions
journalctl -u sudo --since "48 hours ago" | grep "session opened for user root"
```
> **Important:** Standard file-integrity tools (AIDE, Tripwire, debsums, `rpm -Va`) check on-disk hashes and will show the binary as unmodified even after page-cache exploitation. The page cache is cleared naturally by rebooting or `drop_caches`. On a rebooted system, page-cache corruption is gone but the attacker may have already established persistence through other means.
---
## Key IoCs Reference
| Indicator | Value | Confidence |
|---|---|---|
| AF_ALG socket family | `38` (first arg to `socket()`) | Medium โ legitimate uses exist |
| Socket type | `5` (SOCK_SEQPACKET) | Medium |
| SOL_ALG option level | `279` (first arg to `setsockopt()`) | Medium |
| Algorithm string | `authencesn(hmac(sha256),cbc(aes))` | **High** โ unusual outside IPsec ESN |
| Syscall chain | `socket(38)` โ `setsockopt(279)` โ `splice()` | **High** |
| PoC key payload | `0800010000000010` (hex, in setsockopt) | **High** for known PoC |
| Primary PoC target | `/etc/passwd` UID field | Medium |
| Secondary targets | `/usr/bin/su`, `/usr/bin/sudo` | Medium |
| Kernel module | `algif_aead` | Context-dependent |
---
*Detection package maintained against official PoC at [theori-io/copy-fail-CVE-2026-31431](https://github.com/theori-io/copy-fail-CVE-2026-31431). If you observe exploitation variants not covered by these rules, please open an issue.*