Detect and mitigate CVE-2026-31431 (Copy Fail) on Linux systems.
Project description
copyfail-guard
A zero-dependency Python CLI that detects CVE-2026-31431 ("Copy Fail") on Linux systems and applies the modprobe-level mitigation. It supports Debian/Ubuntu, RHEL/Rocky/AlmaLinux, Fedora, and SUSE.
What is CVE-2026-31431?
A logic bug in the kernel algif_aead (AF_ALG AEAD socket) interface lets an
unprivileged local user perform a controlled 4-byte write into the page cache of
any readable file, leading to root privilege escalation. CVSS 7.8. The flaw has
been present since kernel 4.14 and was patched in stable releases starting in
April 2026.
What this tool does
- detect — combine four signals (kernel version,
/proc/modules,modules.builtin, modprobe blacklist) into one of six verdicts:patched,mitigated,vulnerable,unmitigable_builtin,not_applicable,unknown. - fix — write
/etc/modprobe.d/cve-2026-31431-copyfail-guard.confwithinstall algif_aead /bin/false, then runmodprobe -r algif_aead. It does not call your package manager — instead it prints the recommended kernel upgrade command for your distribution so you can review and run it yourself.
Install
pip install copyfail-guard
Or run from a checkout without installing:
PYTHONPATH=src python3 -m copyfail_guard detect
Usage
copyfail-guard [--json] [--dry-run] [--quiet] [--root PATH] [detect|fix]
detect (default)
$ copyfail-guard
[copyfail-guard] CVE-2026-31431 (Copy Fail) — VULNERABLE
Distribution: Ubuntu 24.04.1 LTS (debian family)
Kernel: 6.8.0-50-generic (branch 6.12, fixed at 6.12.85)
Module: algif_aead — loaded as .ko
Mitigation: none
Recommended actions:
1. Apply mitigation now:
sudo copyfail-guard fix
2. Update the kernel for a permanent fix:
Update the kernel on this system to 6.12.85 or later (whatever your
distribution ships once it has integrated the CVE-2026-31431 fix), then
reboot.
fix
$ sudo copyfail-guard fix
[copyfail-guard] fix — OK
[ ok ] Pre-flight checks (Linux, host, root)
[ ok ] Wrote modprobe blacklist [/etc/modprobe.d/cve-2026-31431-copyfail-guard.conf]
[ ok ] Unloaded algif_aead [algif_aead]
[ ok ] Appended audit record [/var/log/copyfail-guard.log]
Next step for a permanent fix:
Update the kernel to a CVE-2026-31431-patched version using your
distribution's normal update mechanism, then reboot.
The fix is intentionally minimal: it writes a modprobe blacklist and unloads
the module. It does not call your package manager. Updating the kernel
itself is up to you — use apt/dnf/zypper (or your configuration
management tool) however your environment normally handles security updates.
Always preview with --dry-run first.
JSON output
--json emits a structured document on stdout, suitable for jq/Ansible/SOAR pipelines:
$ copyfail-guard --json detect | jq .verdict
"vulnerable"
Exit codes
| Code | Meaning |
|---|---|
| 0 | safe — verdict is patched, mitigated, or not_applicable; or fix succeeded |
| 1 | vulnerable — verdict is vulnerable or unmitigable_builtin |
| 2 | error — could not determine state, refused due to preconditions, fix failed |
Mitigation reversal
To remove the mitigation after upgrading to a patched kernel:
sudo rm /etc/modprobe.d/cve-2026-31431-copyfail-guard.conf
sudo systemctl reboot
Notes
- Container hosts. copyfail-guard refuses to apply
fixfrom inside a container because/proc/modulesreflects the host but the container has no authority to load or unload modules. Run it on the host instead. - Built-in
algif_aead. Some custom kernels compilealgif_aeaddirectly into the image (CONFIG_CRYPTO_USER_API_AEAD=y). modprobe-level mitigation has no effect there; the only fix is upgrading the kernel. The detector reportsunmitigable_builtinin this case. blacklist algif_aeadvsinstall algif_aead /bin/false. Both block auto-loading viarequest_module, but the latter cannot be overridden with an explicitmodprobeinvocation. copyfail-guard installs the stronger form.- SELinux/AppArmor. Writes to
/etc/modprobe.d/inheritsystem_u:object_r:modules_conf_t:s0from the parent directory on RHEL; no relabel is needed. - initramfs/dracut.
algif_aeadis not included in the boot image on any major distribution, soupdate-initramfs -u/dracut -fis not required after installing the blacklist.
Development
PYTHONPATH=src python3 -m unittest discover tests
The test suite uses fixture filesystems under tests/fixtures/ so it runs on
macOS without needing real Linux. Each fixture contains a synthetic
/etc/os-release, /proc/modules, /sys/module/, and
/lib/modules/<rel>/{modules.dep,modules.builtin} tree.
License
Apache 2.0 — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file copyfail_guard-0.0.2.tar.gz.
File metadata
- Download URL: copyfail_guard-0.0.2.tar.gz
- Upload date:
- Size: 35.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a788fa973978a0cd8d573e373a6563be7322a63c852802dbe676e98856a8be54
|
|
| MD5 |
18f20cc6359dfb4bf03f3bfa822067a4
|
|
| BLAKE2b-256 |
1b602c4866d2c3c54bba0fe3c7808e00ec8312396d0d546299ec51f510d147dd
|
Provenance
The following attestation bundles were made for copyfail_guard-0.0.2.tar.gz:
Publisher:
python-publish.yml on ctzisme/copyfail-guard
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
copyfail_guard-0.0.2.tar.gz -
Subject digest:
a788fa973978a0cd8d573e373a6563be7322a63c852802dbe676e98856a8be54 - Sigstore transparency entry: 1436163295
- Sigstore integration time:
-
Permalink:
ctzisme/copyfail-guard@dd50e98703c41089ad2c06af6b715d181e9d60c7 -
Branch / Tag:
refs/tags/v0.0.2 - Owner: https://github.com/ctzisme
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@dd50e98703c41089ad2c06af6b715d181e9d60c7 -
Trigger Event:
release
-
Statement type:
File details
Details for the file copyfail_guard-0.0.2-py3-none-any.whl.
File metadata
- Download URL: copyfail_guard-0.0.2-py3-none-any.whl
- Upload date:
- Size: 28.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6c89b928ff50164da607c36b1df52b7eb8203addbafd6991a8b099ead33e8bcc
|
|
| MD5 |
328745ba127ce623ffcf555ba828a54a
|
|
| BLAKE2b-256 |
0fa2652651bde56a0228950d81f4f2e96967962fce6707af1626428a0ce77439
|
Provenance
The following attestation bundles were made for copyfail_guard-0.0.2-py3-none-any.whl:
Publisher:
python-publish.yml on ctzisme/copyfail-guard
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
copyfail_guard-0.0.2-py3-none-any.whl -
Subject digest:
6c89b928ff50164da607c36b1df52b7eb8203addbafd6991a8b099ead33e8bcc - Sigstore transparency entry: 1436163297
- Sigstore integration time:
-
Permalink:
ctzisme/copyfail-guard@dd50e98703c41089ad2c06af6b715d181e9d60c7 -
Branch / Tag:
refs/tags/v0.0.2 - Owner: https://github.com/ctzisme
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@dd50e98703c41089ad2c06af6b715d181e9d60c7 -
Trigger Event:
release
-
Statement type: