The vulnerability exists because the authencesn template fails to clear the
SCATTERLIST_BIT_MUTABLE flag when accepting pipe-sourced pages into its AEAD destination scatterlist — allowing page-cache pages marked read-only to be written to. The attacker splices a setuid binary's read-only pages through a pipe into an AF_ALG socket, triggers the AEAD write path, and achieves a controlled 4-byte overwrite of the binary's ELF entry point in page-cache.The result: any low-privileged user becomes root in a single script execution with 100% reliability, no race condition, and zero forensic artifacts on disk.
- Run kernel version inventory across entire Linux fleet:
for host in $(cat inventory.txt); do ssh $host 'echo "$HOSTNAME: $(uname -r)"'; done > kernel_versions.txt - Identify vulnerable systems (kernels 4.13–6.18): flag all unpatched as CRITICAL — report count to CISO within 2 hours
- Categorize by risk tier: K8s nodes / CI-CD runners → CRITICAL · Multi-user servers → HIGH · Cloud VMs → HIGH · Developer laptops → MEDIUM
- K8s clusters:
kubectl get nodes -o wide— SSH to each node, rununame -r. Every node = CRITICAL if unpatched - Document total vulnerable count by tier for compliance reporting
- Deploy algif_aead module blacklist to ALL CRITICAL systems via Ansible (see command in Overview tab)
- Verify mitigation:
ansible all -m shell -a 'lsmod | grep algif_aead; echo CLEAR' -b— any non-empty lsmod result = not mitigated - For Kubernetes: apply seccomp profile blocking socket(AF_ALG) to all pod specs via admission webhook or manual annotation
- Update initramfs to persist blacklist across reboots:
update-initramfs -u(Ubuntu/Debian) ordracut --force(RHEL/SUSE) - Identify apps using AF_ALG for legitimate crypto (rare) — coordinate with owners before blacklisting on those systems
- Deploy auditd AF_ALG rule:
auditctl -a always,exit -F arch=b64 -S socket -F a0=0x26 -F uid!=0 -k copy_fail_afalg - Deploy auditd splice rule:
auditctl -a always,exit -F arch=b64 -S splice -F uid!=0 -k copy_fail_splice - Deploy auditd LPE rule:
auditctl -a always,exit -F arch=b64 -S execve -F uid!=0 -F euid=0 -k copy_fail_lpe - Forward auditd logs to SIEM in real-time via audisp-remote or rsyslog — do NOT rely on periodic polling
- Deploy eBPF real-time monitor:
bpftrace -e 'tracepoint:syscalls:sys_enter_socket /args->family==38 && uid>0/ { printf("AF_ALG: pid=%d uid=%d comm=%s\n",pid,uid,comm); }' - Configure SIEM alert: uid=0 process with no sudo/su ancestor in last 60s — core LPE detection rule, deploy immediately
- Set up lab test environment — clone representative VMs (Ubuntu 22.04, RHEL 9, Debian 12, SUSE 15) and test patch before production rollout
- Pre-download patched kernel packages to avoid bandwidth issues during rollout:
apt-cache show linux-image-generic | grep Version - Document Kubernetes rolling update procedure: cordon → drain → patch → reboot → uncordon — one node at a time, not parallel
- Raise emergency change request in ITSM — priority EMERGENCY, SLA 48h CRITICAL / 7 days HIGH tier systems
- Verify patch verification command:
uname -rshows patched version +lsmod | grep algif_aeadreturns empty
- IF ACTIVE COMPROMISE SUSPECTED: capture memory first —
insmod lime.ko path=/mnt/mem.lime format=limebefore any other action - Export auditd logs to external storage immediately:
cp -a /var/log/audit/ /secure/evidence/$(hostname)_$(date +%Y%m%d)/ - Capture current process list:
ps auxef > /tmp/ev/ps.txt && ss -tulpna > /tmp/ev/ss.txt && lsmod > /tmp/ev/lsmod.txt - Check for active AF_ALG sockets now:
cat /proc/*/net/af_alg 2>/dev/null— any entry from non-root uid is critical
- Hunt AF_ALG by non-root in auditd:
ausearch -k copy_fail_afalg | grep 'uid=[^0]'— any hit = HIGH confidence exploit attempt - Hunt splice from Python:
ausearch -k copy_fail_splice | grep python— splice from non-root Python + setuid binary FD = exploit chain confirmed - Check dmesg for kernel errors:
dmesg | grep -iE '(aead|algif|splice.*error)' - Verify algif_aead not loaded:
lsmod | grep algif— if loaded post-mitigation, investigate immediately (attacker or failed mitigation) - Check setuid binary access:
find /usr/bin -perm -4000 -newer /var/log/syslog 2>/dev/null
- Hunt uid=0 without auth path:
ausearch -m EXECVE | awk '$0~/uid=0/ && $0!~/(sudo|su|login|sshd|cron)/'— this is the LPE detection signature - Check auth logs:
grep 'session opened for user root' /var/log/auth.log— cross-reference against sudo/su entries - Compare /etc/passwd and /etc/shadow against backup — attacker may add backdoor root account post-exploitation
- Hunt new SUID binaries:
find / -perm -4000 -newer /var/log/boot.log 2>/dev/null - Review last logins:
last -n 50 | head— root logins at unusual hours = suspect
- Hunt Python from temp dirs:
ausearch -m EXECVE | grep -E '(/tmp|/dev/shm|/run/user).*python'— Copy Fail PoC always runs from temp dir - Hunt 732-byte Python scripts:
find / -name '*.py' -size 732c -newer /var/log/dpkg.log 2>/dev/null— exact PoC size - Container check:
kubectl exec -it <pod> -- uname -r— pod kernel = host kernel, confirm host unpatched = all pods exposed - Retroactive hunt: search auditd logs from April 22 2026 (7 days pre-disclosure) for copy_fail_afalg key hits — threat actors hunt for 0-days before public disclosure
- Copy Fail modifies page-cache ONLY — rebooting clears the exploit payload but does NOT remove attacker persistence if they planted an SSH key, SUID shell, or cronjob post-root
- If attacker achieved root: assume full host compromise — credential harvest, metadata API access, Docker socket abuse all possible within seconds of root
- DO NOT reimage before forensic evidence capture — memory and audit logs first, then decide on remediation path
- Fleet-wide Ansible deployment:
ansible all -m shell -a "echo 'blacklist algif_aead' > /etc/modprobe.d/blacklist-copy-fail.conf && modprobe -r algif_aead 2>/dev/null" -b - Verify fleet:
ansible all -m shell -a 'lsmod | grep algif_aead; echo CLEAR' -b | grep -v CLEAR— any non-empty = not mitigated - For module in use:
fuser /dev/crypto 2>/dev/null— identify process using it, coordinate with app owner before forced removal - Persist blacklist across reboots:
update-initramfs -u(Debian/Ubuntu) ordracut --force(RHEL/SUSE)
- Apply seccomp profile blocking AF_ALG socket to all pods — deploy via admission webhook or per-pod securityContext annotation
- Enforce AppArmor/SELinux profile denying socket(family=38) — update profiles and apply to all running pods
- Audit privileged pods:
kubectl get pods --all-namespaces -o json | jq '.items[] | select(.spec.containers[].securityContext.privileged==true) | .metadata' - Verify all node kernel versions via debug containers:
kubectl debug node/<name> -it --image=busybox -- uname -r
- IF exploitation confirmed: isolate via EDR quarantine maintaining EDR management channel — do NOT full network cut if EDR needed for forensics
- Revoke SSH keys and cloud IAM credentials for any account with a session on the compromised host
- Cloud instances: take snapshot before shutdown for forensics, then stop instance (AWS:
aws ec2 stop-instances) - Assess breach notification obligations — if attacker accessed regulated data (PII, PCI, health) post-root: GDPR 72h clock may be running, notify DPO immediately
- Fleet kernel check:
ansible all -m shell -a 'uname -r' -b— all outputs must show patched version - Fleet module check:
ansible all -m shell -a 'lsmod | grep algif_aead; echo CLEAR' -b | grep -v CLEAR— any hit = module still loaded - Run PoC in isolated lab on patched system — should exit with ENODEV or module not found error, document result
- Remove temporary blacklist files after patch confirmed:
ansible all -m file -a 'path=/etc/modprobe.d/blacklist-copy-fail.conf state=absent' -b - Update CMDB/asset inventory with patched kernel versions and patch completion timestamp
- CISO sign-off: confirm 100% of CRITICAL/HIGH tier systems show patched kernel version before closing IR
- Patch coverage report: vulnerable system count at T=0 vs patched at T=now — document for compliance
- Re-enable services temporarily disabled during patching — verify clean restart:
systemctl status <service> - Kubernetes cluster health:
kubectl get pods --all-namespaces | grep -v Running— investigate any non-running pods
- Search pre-patch audit logs for AF_ALG activity from April 22:
ausearch -k copy_fail_afalg --start 04/22/2026 | grep 'uid=[^0]' - Hunt splice from Python pre-patch:
ausearch -k copy_fail_splice --start 04/22/2026 | grep python - Root login review:
last | grep root | awk '$3!~/tty|pts/'— unexpected root sessions in the window - New SUID binaries:
find /usr/bin /usr/sbin -perm -4000 -newer /etc/shadow— attacker post-root may add SUID persistence - SSH authorized_keys audit: check /root/.ssh/authorized_keys and all user ~/.ssh/ for unauthorized entries
- Cron persistence check: inspect /var/spool/cron/crontabs/root and /etc/cron.d/ modification times vs incident window
- Keep AF_ALG auditd rules active for 30 days — monitor for retry attempts from persistent attackers or script kiddies
- Keep uid=0 transition alert active — any hit post-patch could indicate different LPE or previously planted backdoor activating
- SIEM alert: Python execution from /tmp, /dev/shm, /run/user by non-root — keep active permanently (low FP in production)
- Weekly setuid binary integrity check:
sha256sum /usr/bin/su /usr/bin/passwd /usr/bin/sudo— diff against baseline for 4 weeks
- Test crypto operations (dm-crypt/LUKS are NOT affected by algif_aead blacklist):
cryptsetup status <volume> - TLS functionality test:
openssl s_client -connect google.com:443 2>/dev/null | grep 'Verify return' - Container workload health:
kubectl get pods --all-namespaces | awk '$4!="Running" && $4!="Completed"' - Application smoke tests on patched systems — verify all critical services function normally after kernel update
- If patch took >72h to fully deploy to CRITICAL systems: mandatory post-mortem on patching pipeline — target SLA must be revised
- Implement automated kernel version monitoring (Wazuh, Lynis, AWS Inspector) — continuous compliance vs known-vulnerable kernel list
- Establish kernel patch SLA policy: kernel LPE with public PoC = 48h CRITICAL tier, 7 days HIGH tier — document in vulnerability management policy
- Implement mandatory Kubernetes default seccomp profiles: restricts AF_ALG and many other dangerous syscalls without custom policy
- Add kernel hardening sysctl:
sysctl kernel.unprivileged_af_alg=0(if available in your kernel) — directly disables unprivileged AF_ALG
- Promote AF_ALG socket detection to PERMANENT SIEM rule — not just during Copy Fail response. AF_ALG by non-root is always suspicious
- Tune uid=0 transition rule: review false positive rate post-incident, adjust sudo/su/PAM exclusions — target: <1 FP per day per 1000 systems
- Deploy Python-from-temp-dir rule permanently — low FP in production, high signal for LPE attempts
- Schedule 30-day purple team exercise: test AF_ALG detection, LPE detection chain, post-exploit persistence detection — validate what SIEM actually catches vs what we think it catches
- Contribute Sigma rules to SigmaHQ GitHub — share Copy Fail detection rules with community
- Share IOCs with sector ISAC, national CERT, GCC-CERT if applicable
- Brief executive leadership: 9-year scope, 100% reliability, zero-disk-write stealth — justifies investment in continuous kernel monitoring and faster patch pipeline
- Publish internal post-incident report within 2 weeks: timeline, gaps identified, improvements made, metrics (MTTD, MTTR)
•
algif_aead module loaded or built-in•
AF_ALG socket family accessible• No mitigation applied (blacklist/grubby)
• Patched kernel NOT installed
→ "System CAN be exploited"
• auditd: splice() by Python PID (syscall=275)
• auth.log:
su entry with missing username• auditd: uid≠0 → euid=0 without sudo ancestor
• Filesystem: new SSH keys, SUID bins, cron jobs
→ "System WAS exploited"
auditd was NOT running during the exploitation window (April 29 onwards), you have no syscall-level evidence. Fall back to auth.log analysis (Step 2), filesystem artifact checks (Step 6), and SIEM behavioral anomalies. Deploy auditd rules NOW to catch future attempts. Zero disk writes means traditional file integrity monitoring (AIDE, OSSEC, Tripwire) will not detect the initial exploit — only post-exploitation persistence.
CRITICAL UPDATE: CloudLinux discovered that the widely recommended modprobe blacklist workaround does NOT work on CloudLinux, AlmaLinux, Rocky Linux, or any RHEL-family distribution. The algif_aead module is compiled directly into the kernel (CONFIG_CRYPTO_USER_API_AEAD=y), not as a loadable module. The blacklist commands execute without errors but leave the system completely unprotected — creating a false sense of security.
Phase 1 (Preparation) and Phase 3 (Containment) mitigation steps referencing modprobe -r algif_aead and blacklist algif_aead are ineffective on RHEL/CentOS/AlmaLinux/Rocky/CloudLinux/Oracle Linux. Replace with the grubby-based kernel command line approach below.
Correct mitigation for RHEL-family (requires reboot):
CloudLinux Imunify360 is actively detecting published IOCs for CVE-2026-31431 and using extended heuristics to identify and mitigate currently observed exploitation attempts. This confirms the vulnerability is being actively exploited in the wild — not just theoretical.
RedPacket Security's SSVC assessment has classified this as "active exploitation" — rated as an urgent, priority remediation item for all affected Linux kernel systems.
Wiz security researchers published a detailed analysis identifying a new post-exploitation detection signal in /var/log/auth.log. When Copy Fail corrupts the /usr/bin/su binary in page-cache and the attacker executes it, the su PAM log entry is missing the invoking username — a field that is always present in legitimate su usage.
Normal su entry:
Copy Fail exploitation su entry:
Hunt query for this signal:
Add this as a new IOC to your detection rules. The missing-username su log entry is a high-confidence post-exploitation signal with very low false positive rate. Add to Phase 2 (Identification) and IOC table.
dnf clean metadata && dnf upgradeyum update kernela664bf3d603d merged in 7.0-rc7Multiple vendors confirmed that because the Linux page cache is shared across all processes on a host — including across container boundaries — CVE-2026-31431 functions as a container escape primitive. A compromised container can corrupt setuid binaries visible to other containers and the host kernel, escalating from container-level access to full host root.
Additional confirmation: Alexander Peslyak (Solar Designer), founder of the Openwall Project, independently verified the exploit works on Rocky Linux 9.7.