Do you know which of your Linux servers are vulnerable right now?
Two critical Linux kernel vulnerabilities are being actively exploited. Dirty Frag targets the IP fragment reassembly modules that almost every Linux server has loaded by default. Copy Fail targets the AF_ALG cryptographic subsystem's AEAD interface. Both can allow an attacker to gain escalated local privileges, and both have interim mitigations you can deploy right now, before the kernel patches land.
The first question every team needs to answer is not "how do we fix it?" but "how many of our systems are actually exposed?" Not tomorrow, after someone runs a scanner. Not next week, when the security team finishes their audit. Right now.
If you are running Puppet, the answer is already within reach. You just need a fact.
Add these to your Puppetfile. That is it.
mod 'albatrossflavour-dirty_frag', '1.0.1'
mod 'albatrossflavour-copy_fail', '1.0.0'
Each of these open-source modules, that I have published to the Forge, ship a custom structured fact that reports vulnerability exposure on every node. No class to include. No Hiera changes. No manifest edits. Next Puppet run, the data is there.
- dirty_frag reports exposure to Dirty Frag (CVE-2026-43284 and CVE-2026-43500)
- copy_fail reports exposure to Copy Fail (CVE-2026-31431)
See where you stand
Once deployed, every node reports its exposure state as structured data. Here is what the output looks like.
dirty_frag
{
"esp4": {
"loaded": true,
"blocked": true,
"available": true
},
"esp6": {
"loaded": false,
"blocked": false,
"available": true
},
"rxrpc": {
"loaded": false,
"blocked": false,
"available": true
},
"vulnerable": true,
"reboot_required": true
}
copy_fail
{
"algif_aead": {
"type": "builtin",
"loaded": false,
"active": true,
"blocked": false,
"available": true
},
"initcall_blacklisted": false,
"vulnerable": true,
"mitigated": false,
"reboot_required": false
}
Both facts surface the same two summary keys that give you the answers you actually care about. vulnerable is true if the exploitable module is active. reboot_required is true if you have applied the mitigation but the module is still sitting in kernel memory.
That reboot_required flag is the one that catches people. You apply the mitigation, see the block in place, and assume you are safe. But the module is still loaded and exploitable until the machine restarts. The facts make this gap visible.
Query your entire fleet in one line
The facts land in PuppetDB like any other structured fact. No extra tooling, no scheduled scans, no agents phoning home to a separate platform. It is just data, maintained automatically every Puppet run.
Show me every node vulnerable to Dirty Frag:
puppet query 'facts[certname, value] { name = "dirty_frag" and value.vulnerable = true }'
Show me every node vulnerable to Copy Fail:
puppet query 'facts[certname, value] { name = "copy_fail" and value.vulnerable = true }'
Show me nodes where the Dirty Frag block is applied but a reboot is still needed:
puppet query 'facts[certname, value] { name = "dirty_frag" and value.reboot_required = true }'
Show me nodes where algif_aead is built into the kernel (the harder mitigation path):
puppet query 'facts[certname, value] { name = "copy_fail" and value.algif_aead.type = "builtin" }'
This is the bit that makes Puppet's model shine. You are not running a point-in-time scan. The data updates every run, automatically. As nodes get patched, rebooted, or have blocks applied, the numbers go down on their own. You can watch your exposure shrink in real time without maintaining anything.
What makes a system vulnerable?
Dirty Frag
The Dirty Frag vulnerability sits in three Linux kernel modules used for IP fragment reassembly: esp4, esp6, and rxrpc. If any of those modules is loaded, the system is exposed. The two CVEs chain together to allow privilege escalation and remote code execution through these modules.
These modules are almost universally loaded on production Linux servers. If you are running iptables, firewalld, Docker, Kubernetes, or any network policy enforcement, odds are at least esp4 is there. This one affects nearly everything.
Copy Fail
The vulnerability is a use-after-free in the AF_ALG subsystem's AEAD interface (algif_aead). An unprivileged user can trigger it by opening an AF_ALG socket and exercising the AEAD code path in a specific way.
algif_aead is present on most stock kernels but rarely used for legitimate work. The main consumers are some VPN implementations that offload crypto to the kernel, kcapi-tools, and certain FIPS-certified configurations. On systems where the module is loadable, an attacker can force-load it themselves just by opening the socket. On systems where it is built-in, it may already be active regardless of use.
Why module presence, not kernel version?
The real fix for both vulnerabilities is a kernel patch, but every distribution ships their own patched versions on their own schedules with their own version numbers. Tracking "which kernel version is safe" across Red Hat, Ubuntu, SUSE, Amazon Linux, and the rest is a moving target that goes stale the day you publish it. Module presence is the reliable signal: if the vulnerable module is active, you are exposed, regardless of kernel version.
This is also what the vendor advisories recommend. Red Hat's RHSB-2026-003 and the equivalent Ubuntu and SUSE bulletins all point to the same interim mitigation: prevent the modules from loading using install /bin/false.
When you want Puppet to enforce the block
The facts give you visibility. If you also want Puppet to actively prevent the modules from loading, include the classes.
Dirty Frag
class { 'dirty_frag':
mitigate_esp4 => true,
mitigate_esp6 => true,
mitigate_rxrpc => true,
}
Copy Fail
class { 'copy_fail':
mitigate_algif_aead => true,
}
Both classes write install <module> /bin/false directives to modprobe.d configuration files. From that point on, any attempt to load those modules (whether by autoloading, a dependency chain, or an explicit modprobe) will run /bin/false instead of loading the actual module code. The module simply cannot get into the kernel.
This is worth understanding because it is stronger than the kernel's blacklist directive. A blacklist entry only prevents autoloading, it does not stop explicit modprobe calls. install /bin/false intercepts the load at every entry point.
If the module was already loaded before the block was applied, it stays in memory until the next reboot. The reboot_required flag in both facts makes this gap visible.
This is declarative and safe. Puppet manages the config file, ensures the desired state on every run, and the classes are entirely opt-in. If your patching process handles the fix, or you are rolling out kernel updates, you might not need them at all. The facts alone give you the visibility to track progress.
Both modules ship with Hiera data defaults, so if you prefer to drive parameters through your hierarchy, see each module's README for examples.
The built-in module problem (Copy Fail only)
There is a wrinkle with Copy Fail that Dirty Frag does not have. On most stock distribution kernels, algif_aead is compiled directly into the kernel image as a built-in module. It is not a loadable .ko file, so modprobe.d has no effect on it.
For built-in modules, the mitigation is initcall_blacklist=algif_aead_init on the kernel command line (via GRUB configuration). This prevents the module's init function from running on boot. It requires a reboot to take effect.
The copy_fail module does not automate GRUB changes. Getting boot configuration wrong can render a system unbootable. You can manage GRUB with Puppet (using file_line or augeas), but that is out of scope for this module. The fact will report initcall_blacklisted: true once the parameter is in place, and reboot_required: true until the reboot completes.
The type field in the fact output tells you which mitigation path applies to each node:
-
builtin: needsinitcall_blacklist, modprobe.d has no effect -
loadable: the class and modprobe.d approach works -
absent: not vulnerable, nothing to do
Force-unload a module right now (with care)
Sometimes you cannot wait for a reboot. Both modules ship a Bolt task that removes the module from the running kernel immediately:
bolt task run dirty_frag::unload module=esp4 --targets servers
bolt task run copy_fail::unload module=algif_aead --targets servers
A word of caution. Unloading a kernel module is not the same as flipping a config switch. If the module is actively in use (for example, esp4 underpins IPsec tunnels, esp6 handles IPv6 ESP, and rxrpc is used by AFS), pulling it out from under a running service can drop connections, crash VPN tunnels, or cause dependent subsystems to fail. This is exactly why the Puppet classes do not do it automatically. The classes apply the block and wait for a reboot. The Bolt tasks give you the lever to pull when you have decided the tradeoff is worth it.
Each task validates the module name, checks it is actually loaded, and gives you structured output. If the module is in use by another kernel subsystem and cannot be unloaded, the task will tell you, and you are back to "apply the block and schedule a reboot".
Test on non-production nodes first. Know what the module is doing on that system before you yank it. If in doubt, the block-and-reboot path is always the safer option.
The unload task only works for loadable modules. Built-in modules cannot be unloaded.
The workflow
- Add the modules to your Puppetfile. Deploy. Done. Every node now reports its exposure.
- Query PuppetDB to see where you stand. One-liner, fleet-wide answer.
- Decide on mitigation. Apply the classes via Hiera for persistent blocking.
- Use Tasks to immediately unload modules on critical systems that cannot wait.
- Watch the numbers drop. The facts update every run. No manual tracking, no spreadsheets, no scheduled scans.
The whole approach is declarative. You tell Puppet what state you want, and it converges towards it. The facts keep reporting reality. The gap between the two is your exposure, and it is always visible.
Get started
Both of these open source modules are available on GitHub:
- albatrossflavour/dirty_frag (Puppet 7/8, no dependencies)
- albatrossflavour/copy_fail (Puppet 7/8, no dependencies)
Both modules have been built for RedHat, CentOS, Ubuntu, Debian, Amazon Linux, and SLES.
Top comments (0)