Mitigate CVE-2026-31431 (Copy-Fail) by Disabling the algif_aead Kernel Module Using Ansible
The CVE is found by Xint Code and it is well-explained here: https://copy.fail
Here is an Ansible playbook that follows the official interim mitigation before a patched kernel is rolled out.
- name: Mitigate CVE-2026-31431 (copy-fail) by disabling the algif_aead kernel module
hosts: all
become: true
gather_facts: true
vars:
blacklist_modules:
- algif_aead
blacklist_file: /etc/modprobe.d/disable-algif.conf
tasks:
- name: Verify target is a Linux host
ansible.builtin.assert:
that:
- ansible_system == "Linux"
fail_msg: This playbook only supports Linux hosts.
- name: Get currently loaded kernel modules
ansible.builtin.command: lsmod
register: lsmod_out
changed_when: false
check_mode: false
- name: Build list of loaded module names
ansible.builtin.set_fact:
loaded_modules: "{{ lsmod_out.stdout_lines[1:] | map('split') | map('first') | list }}"
- name: Pre-check — report module usage before mitigation
vars:
lsmod_lines: "{{ lsmod_out.stdout_lines[1:] }}"
entry: "{{ lsmod_lines | select('match', '^' ~ item ~ '\\s') | list }}"
parts: "{{ (entry[0] | default('')).split(None, 3) }}"
ansible.builtin.debug:
msg: >-
{% if entry | length == 0 -%}
{{ item }}: NOT loaded — module is not in use on this host.
{%- else -%}
{{ item }}: LOADED (size={{ parts[1] }}, refcount={{ parts[2] }}, used_by={{ parts[3] | default('(none)') }}). {% if parts[2] | int > 0 or (parts | length > 3 and parts[3] | trim != '-') %}WARNING: module appears in use — review used_by/refcount before unloading.{% else %}Refcount is 0 and no dependents — safe to unload.{% endif %}
{%- endif %}
loop: "{{ blacklist_modules }}"
- name: Persist kernel module blacklist
ansible.builtin.copy:
dest: "{{ blacklist_file }}"
owner: root
group: root
mode: "0644"
content: |
# CVE-2026-31431 interim mitigation
# Replaces the load action for the listed modules with /bin/false,
# which blocks both automatic and on-demand loading. Remove this
# file once a patched kernel is rolled out.
{% for mod in blacklist_modules %}
install {{ mod }} /bin/false
{% endfor %}
- name: Unload blacklisted kernel modules that are currently loaded
ansible.builtin.modprobe:
name: "{{ item }}"
state: absent
loop: "{{ blacklist_modules }}"
when: item in loaded_modules
- name: Verify modprobe is blocked for blacklisted modules
ansible.builtin.command: "modprobe {{ item }}"
loop: "{{ blacklist_modules }}"
register: verify_modprobe
failed_when: verify_modprobe.rc == 0
changed_when: false
check_mode: false
- name: Verify blacklisted modules are not loaded
ansible.builtin.shell: "set -o pipefail && lsmod | awk '{print $1}' | grep -Fxq {{ item }}"
args:
executable: /bin/bash
loop: "{{ blacklist_modules }}"
register: verify_loaded
failed_when: verify_loaded.rc == 0
changed_when: false
check_mode: false