Articles on: ggRock

Linux Kernel Local Privilege Escalation — Fragnesia, Dirty Frag, Copy-Fail, ssh-keysign-pwn, nf_tables Typo, CIFSwitch, DirtyClone

Linux Kernel Local Privilege Escalation — Fragnesia, Dirty Frag, Copy-Fail, ssh-keysign-pwn, nf_tables Typo, CIFSwitch, DirtyClone

Severity: Critical | Last Updated: 2026-06-27 | CVEs: CVE-2026-46300, CVE-2026-43284, CVE-2026-31431, CVE-2026-46333, CVE-2026-23111, CVE-2026-46243, CVE-2026-43503

CVE

Codename

Disclosed

CVSS

Patch Available

CISA KEV

CVE-2026-46300

Fragnesia

2026-05-13

7.8 High

Yes

No

CVE-2026-43284

Dirty Frag

2026-05-13

7.8 High

Yes

No

CVE-2026-31431

Copy-Fail

2026-04-29

7.8 High

Yes

Yes — deadline 2026-05-15

CVE-2026-46333

ssh-keysign-pwn

2026-05-15

7.8 High

Yes

No

CVE-2026-23111

nf_tables Typo

2026-06-08

7.8 High

Yes

No

CVE-2026-46243

CIFSwitch

2026-05-27

7.8 High

Yes

No

CVE-2026-43503

DirtyClone

2026-06-26

8.8 High

Yes

No


Summary

Seven Linux kernel local privilege escalation vulnerabilities have been publicly disclosed in rapid succession, each allowing an unprivileged local user to gain root access. Public proof-of-concept exploits exist for all seven. All should be treated as actively exploitable.

They fall into three overlapping groups by mechanism. The first three (Fragnesia, Dirty Frag, Copy-Fail) corrupt the page cache via a network stack bug, requiring no special capabilities. ssh-keysign-pwn is a ptrace/pidfd_getfd race during process exit that steals file descriptors from dying privileged processes. The two namespace-reachable CVEs (nf_tables Typo, CIFSwitch) are reached through unprivileged user namespaces and mitigated by a single namespace restriction. DirtyClone is a hybrid: it shares the page-cache corruption technique of the first group and the unprivileged user namespace requirement of the third group, making it the highest-severity entry at CVSS 8.8.

CVE-2026-31431 (Copy-Fail) has been added to the CISA Known Exploited Vulnerabilities catalog with a mandatory remediation deadline of 2026-05-15 for US federal civilian agencies.

Workarounds are available and effective for all seven. Patched kernels are available for all supported Debian releases.


Am I Affected?

Yes, if all of the following are true:

  • You are running Linux
  • Your kernel predates the patched versions for your distribution (see Priority 1 below)
  • An untrusted local user can log in or execute code on the system

Cloud VMs, shared hosting environments, container hosts with untrusted workloads, and developer machines with shared access are all in scope. Systems where only trusted administrators have shell access are lower risk but should still be patched.

The namespace-reachable CVEs (nf_tables Typo, CIFSwitch, and DirtyClone) additionally require unprivileged user namespaces to be enabled — the default on most distributions. CIFSwitch further requires cifs-utils to be installed. DirtyClone also requires esp4/esp6 modules to set up a loopback IPsec tunnel.


Vulnerability Details

CVE-2026-46300 — Fragnesia

Disclosed: 2026-05-13 | CVSS: 7.8 (High)

Affected subsystem: XFRM ESP-in-TCP (espintcp ULP)

When a TCP socket switches to espintcp upper-layer protocol mode after file data has already been spliced into its receive queue, the kernel mistakenly treats those queued file-backed pages as ESP ciphertext. This causes one byte of an AES-GCM keystream to be XORed into a read-only file's kernel page cache entry.

By constructing a lookup table of IV nonces that produce each possible keystream byte, an attacker can flip any byte in a cached file to any value — one byte per invocation. The exploit uses this to overwrite the first 192 bytes of /usr/bin/su in the page cache with a stub that calls setresuid(0,0,0) and launches a shell.

The on-disk binary is never modified. Only the in-memory page cache is affected. A compromised binary persists in RAM and will produce a root shell on every invocation until the page cache is explicitly flushed or the system is rebooted.

Discovered by: William Bowling, V12 Security Team Public PoC: https://github.com/v12-security/pocs/tree/main/fragnesia Reference: https://cybersecuritynews.com/fragnesia-linux-vulnerability/

CVE-2026-43284 — Dirty Frag

Disclosed: 2026-05-13 | CVSS: 7.8 (High)

Affected subsystem: XFRM fragment coalescing

A related logic flaw in how the kernel coalesces socket buffer fragments causes it to "forget" that a fragment is shared, corrupting memory it was not supposed to touch. The attack surface and exploitation technique are similar to Fragnesia, and the same modules are involved.

Reference: https://cybersecuritynews.com/dirty-frag-linux-vulnerability/

CVE-2026-31431 — Copy-Fail

Disclosed: 2026-04-29 | CVSS: 7.8 (High) | CISA KEV: Yes

Affected subsystem: AF_ALG kernel crypto API (algif_aead)

A logic flaw in the AEAD crypto socket path allows page cache corruption via the AF_ALG socket family (Family 38). The algif_aead module is the direct attack surface; af_alg is its parent and must also be disabled.

Reference: https://cybersecuritynews.com/linux-kernel-0-day-vulnerability-exploited/

CVE-2026-46333 — ssh-keysign-pwn

Disclosed: 2026-05-15 | CVSS: 7.8 (High)

Affected subsystem: ptrace / pidfd_getfd — process exit race

__ptrace_may_access() skips its dumpable check when the target task's mm is NULL. During do_exit(), the kernel runs exit_mm() before exit_files(), creating a window where a privileged process has dropped its memory mappings but still holds its open file descriptors. An unprivileged process running under the same UID can call pidfd_getfd(2) in that window and steal open file descriptors from the dying process.

If those descriptors point at root-owned files opened before privilege drop — such as SSH host keys opened by ssh-keysign before permanently_set_uid(), or /etc/shadow opened by chage before setreuid() — the attacker now holds a read handle on those files.

Unlike the page-cache CVEs, this vulnerability does not corrupt in-memory binaries. It is a file descriptor theft primitive.

Discovered by: Qualys Public PoC: https://github.com/0xdeadbeefnetwork/ssh-keysign-pwn Upstream fix: https://github.com/torvalds/linux/commit/31e62c2ebbfdc3fe3dbdf5e02c92a9dc67087a3a Reference: https://almalinux.org/blog/2026-05-15-ssh-keysign-pwn-cve-2026-46333/

CVE-2026-23111 — nf_tables Typo

Disclosed: 2026-06-08 (PoC) | CVSS: 7.8 (High) | Upstream patch: 2026-02-05

Affected subsystem: nf_tables (Netfilter packet filtering)

A single inverted check in nft_map_catchall_activate() causes the kernel to use the wrong sense of an activity check while aborting a failed nf_tables transaction. Each aborted transaction permanently decrements a chain's use counter; once it reaches zero, the chain is freed while a stale reference still points at it, producing a use-after-free. A fully weaponized public exploit achieves root with greater than 99% reliability across Debian Bookworm and Trixie.

nf_tables cannot be disabled on a ggRock host — it backs the firewall. The practical mitigation is denying unprivileged user namespace creation, which closes the exploit's reachability path without touching the firewall stack.

Upstream fix: https://github.com/torvalds/linux/commit/3da1fdf4efbc490041eb4f836bf596201203f8f2 Reference: https://thehackernews.com/2026/06/one-character-linux-kernel-flaw-enables.html

CVE-2026-46243 — CIFSwitch

Disclosed: 2026-05-27 | CVSS: 7.8 (High) | CVE assigned: 2026-06-01

Affected subsystem: CIFS client cifs.spnego upcall + cifs-utils helper

The kernel's cifs.spnego key type did not validate the origin of its key description. An unprivileged user could call request_key("cifs.spnego", fake_description, ...) directly, causing the default request-key rule to launch cifs.upcall as root. A forged description containing an attacker-controlled pid makes the root helper switch into the attacker's namespace, where a namespace-local nsswitch.conf can run attacker code as root — for example, dropping a sudoers.d entry.

On a diskless ggRock boot host, cifs-utils is typically not installed — if cifs.upcall is absent, the host is not exposed. The same unprivileged-user-namespace restriction that mitigates the nf_tables Typo also closes the CIFSwitch reachability path.

Discovered by: Asim Manizada Public PoC: https://github.com/manizada/CIFSwitch Reference: https://heyitsas.im/posts/cifswitch/

CVE-2026-43503 — DirtyClone

Disclosed: 2026-06-26 | CVSS: 8.8 (High — highest in this set) | Patch merged: 2026-05-21

Affected subsystem: Networking packet clone helpers (__pskb_copy_fclone(), skb_shift())

DirtyClone is the fourth variant in the DirtyFrag family and the highest-severity entry here. When the kernel clones a network packet internally, __pskb_copy_fclone() and skb_shift() drop the SKBFL_ZEROCOPY_FRAG flag that marks packet memory as shared with a file on disk. The attacker loads a privileged binary such as /usr/bin/su into the page cache, wires those pages into a network packet, forces a kernel clone, then routes the clone through a loopback IPsec tunnel they control. The AES-GCM decryption step overwrites the binary's login checks in the page cache. The next invocation of su hands over root.

The on-disk binary is never modified; a reboot restores it. File-integrity tools will not detect the attack, and it leaves no audit trail.

The exploit requires CAP_NET_ADMIN to configure the loopback IPsec tunnel. On Debian and Fedora, an unprivileged user obtains this capability by creating a user namespace — the default configuration. Because the page cache is shared at the host level, modifications made inside a namespace affect every process on the machine, which is why CVSS is 8.8 rather than 7.8.

Unlike the other page-cache CVEs in this set, the modification is host-wide — it affects every process on the machine, not just those in the attacker's namespace. Reboot after flushing the cache to fully restore affected binaries.

If harden_all.sh has already run harden_fragnesia.sh and harden_nftables.sh, both DirtyClone gates are already closed. The dedicated script applies and verifies them independently.

Discovered by: JFrog Security Research (exploit walkthrough), Hyunwoo Kim (multi-site patch) Public PoC: https://research.jfrog.com/post/dissecting-and-exploiting-linux-lpe-variant-dirtyclone-cve-2026-43503/ Upstream fix: commit 48f6a5356a33 — https://github.com/torvalds/linux/commit/48f6a5356a33 Reference: https://thehackernews.com/2026/06/new-dirtyclone-linux-kernel-flaw-lets.html


Impact

CVE

Codename

Privilege Required

Race Condition

Root Shell

CVE-2026-46300

Fragnesia

Unprivileged local user

No

Yes

CVE-2026-43284

Dirty Frag

Unprivileged local user

No

Yes

CVE-2026-31431

Copy-Fail

Unprivileged local user

No

Yes

CVE-2026-46333

ssh-keysign-pwn

Unprivileged local user

Soft (exit window)

Yes — via host key / shadow read

CVE-2026-23111

nf_tables Typo

Unprivileged local user + userns

No

Yes — also container escape

CVE-2026-46243

CIFSwitch

Unprivileged local user + userns

No

Yes — via forged upcall + NSS

CVE-2026-43503

DirtyClone

Unprivileged local user + userns

No

Yes — host-wide page cache, CVSS 8.8


Priority 1 — Apply the Upstream Patch (Permanent Fix)

Patched kernels are available for all supported Debian releases. The minimum patched versions are:

Debian Release

Minimum Patched Kernel

Debian 13 Trixie

6.12.85-1

Debian 12 Bookworm

6.1.170-1

Debian 11 Bullseye

5.10.251-3

Update and reboot:

apt update && apt full-upgrade && reboot

Verify your running kernel version after reboot:

uname -r

The patched kernel is available via the standard [security] repository, which is enabled by default on all supported Debian releases. On Debian 13 Trixie, sources configuration has moved from /etc/apt/sources.list to /etc/apt/sources.list.d/debian.sources — the security repository is included in the default debian.sources file.

The minimum patched versions above were validated against Copy-Fail (CVE-2026-31431). The DirtyClone fix (commit 48f6a5356a33) and the nf_tables/CIFSwitch fixes landed on different dates. Confirm patch status for those CVEs against the Debian security tracker links in References if you need version-exact assurance.

Priority 2 — Apply Workaround (If Immediate Patching Is Not Possible)

Each CVE has a dedicated hardening script. The simplest approach is the master script, which fetches and runs all seven in the correct order:

wget -O - https://images.ggleap.com/ManagedServices/Scripts/harden_all.sh | bash -
This mitigation disables IPsec (ESP/RXRPC) for CVE-2026-46300, CVE-2026-43284, and CVE-2026-43503; AF_ALG crypto sockets for CVE-2026-31431; unrestricted ptrace attach for CVE-2026-46333; and unprivileged user namespaces for CVE-2026-23111, CVE-2026-46243, and CVE-2026-43503. Disabling unprivileged user namespaces also breaks rootless containers (Podman, rootless Docker). Review the Caveats section before applying.

The individual scripts are listed below for reference.

harden_fragnesia.sh — CVE-2026-46300

#!/bin/bash
# Fragnesia (CVE-2026-46300) Hardening Script
# Ref: https://cybersecuritynews.com/fragnesia-linux-vulnerability/

if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit 1
fi

echo "--- Fragnesia (CVE-2026-46300) Hardening ---"

MODULES_IN_USE=false
if lsmod | grep -qE "^(esp4|esp6|rxrpc)"; then
echo "[!] WARNING: ESP/RXRPC modules currently loaded."
ip xfrm state 2>/dev/null | grep -q "proto esp" && \
echo "[!] Active IPsec SA detected — unloading will drop tunnels."
MODULES_IN_USE=true
fi

CONF_FILE="/etc/modprobe.d/disable-fragnesia.conf"
echo "[*] Writing blacklist to $CONF_FILE..."
cat <<EOF > "$CONF_FILE"
# Fragnesia (CVE-2026-46300) mitigation — $(date -u +%Y-%m-%dT%H:%M:%SZ)
install esp4 /bin/false
install esp6 /bin/false
install rxrpc /bin/false
EOF
echo "[+] Blacklist written."

if [ "$MODULES_IN_USE" = true ]; then
echo "[!] Skipping module unload — active sessions detected."
else
modprobe -r esp4 esp6 rxrpc 2>/dev/null
lsmod | grep -qE "^(esp4|esp6|rxrpc)" && echo "[!] Unload failed — reboot required." || echo "[+] Modules unloaded."
fi

echo "[*] Flushing page cache..."
sync; echo 1 > /proc/sys/vm/drop_caches
echo "[+] Page cache flushed."

echo "[*] Rebuilding initramfs..."
command -v update-initramfs &>/dev/null && update-initramfs -u

echo "[*] Testing AF_RXRPC socket (Family 33)..."
python3 -c "import socket; socket.socket(33, 2, 0)" 2>/dev/null \
&& echo "[!] FAIL: socket still created — reboot required." \
|| echo "[+] VERIFIED: kernel rejects vulnerable socket type."

harden_net_frag.sh — CVE-2026-43284

#!/bin/bash
# Dirty Frag (CVE-2026-43284) Mitigation Script
# Ref: https://cybersecuritynews.com/dirty-frag-linux-vulnerability/

if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit 1
fi

set -e
CONFIG_FILE="/etc/modprobe.d/dirtyfrag.conf"
VULN_MODULES=("esp4" "esp6" "rxrpc")

echo "--- Dirty Frag (CVE-2026-43284) Mitigation ---"

cat <<EOF > "${CONFIG_FILE}.tmp"
# Dirty Frag (CVE-2026-43284) mitigation — $(date -u +%Y-%m-%dT%H:%M:%SZ)
install esp4 /bin/false
install esp6 /bin/false
install rxrpc /bin/false
EOF
mv "${CONFIG_FILE}.tmp" "$CONFIG_FILE"
echo "[+] Blacklist written to $CONFIG_FILE"

for mod in "${VULN_MODULES[@]}"; do
lsmod | grep -q "^$mod " && { modprobe -r "$mod" 2>/dev/null && echo "[+] $mod unloaded." || echo "[!] $mod unload failed."; } || echo "[*] $mod not loaded."
done

echo "[*] Flushing page cache..."
sync; echo 1 > /proc/sys/vm/drop_caches

echo "[*] Rebuilding initramfs..."
command -v update-initramfs &>/dev/null && update-initramfs -u

echo "[*] Testing AF_RXRPC socket (Family 33)..."
SOCK_ERR=$(python3 -c "import socket; socket.socket(33, 2, 0)" 2>&1) || true
if ! python3 -c "import socket; socket.socket(33, 2, 0)" 2>/dev/null; then
echo "[+] VERIFIED: kernel rejects vulnerable socket type."
else
echo "[!] FAIL: socket still created — reboot required."
fi

harden_crypto.sh — CVE-2026-31431

#!/bin/bash
# Copy-Fail (CVE-2026-31431) Hardening Script
# Mitigates AF_ALG/algif_aead privilege escalation via module blacklist

if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit 1
fi

echo "--- Copy-Fail (CVE-2026-31431) Hardening ---"

CONF_FILE="/etc/modprobe.d/disable-copy-fail.conf"
cat <<EOF > "$CONF_FILE"
# Copy-Fail (CVE-2026-31431) mitigation — $(date -u +%Y-%m-%dT%H:%M:%SZ)
install algif_aead /bin/false
install af_alg /bin/false
alias net-pf-38 off
EOF
echo "[+] Blacklist written to $CONF_FILE"

echo "[*] Unloading modules (child before parent)..."
modprobe -r algif_aead 2>/dev/null
modprobe -r af_alg 2>/dev/null
lsmod | grep -qE "^(algif_aead|af_alg)" && echo "[!] Unload failed — reboot required." || echo "[+] Modules unloaded."

echo "[*] Rebuilding initramfs..."
command -v update-initramfs &>/dev/null && update-initramfs -u

echo "[*] Testing AF_ALG socket (Family 38)..."
python3 -c "import socket; socket.socket(38, 5, 0)" 2>/dev/null \
&& echo "[!] FAIL: socket still created — reboot required." \
|| echo "[+] VERIFIED: kernel rejects AF_ALG socket."

harden_sshkeysignpwn.sh — CVE-2026-46333

#!/bin/bash
# ssh-keysign-pwn (CVE-2026-46333) Hardening Script
# Ref: https://almalinux.org/blog/2026-05-15-ssh-keysign-pwn-cve-2026-46333/

if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit 1
fi

echo "--- ssh-keysign-pwn (CVE-2026-46333) Hardening ---"

SYSCTL_CONF="/etc/sysctl.d/99-ssh-keysign-pwn.conf"
PTRACE_SCOPE_FILE="/proc/sys/kernel/yama/ptrace_scope"

[ ! -f "$PTRACE_SCOPE_FILE" ] && echo "[!] Yama LSM not loaded." && exit 1

PTRACE_PIDS=$(awk '/TracerPid:/ && $2 != "0" {c++} END {print c+0}' /proc/[0-9]*/status 2>/dev/null)
[ "$PTRACE_PIDS" -gt 0 ] && echo "[!] WARNING: $PTRACE_PIDS process(es) being ptraced."

echo "[*] Setting kernel.yama.ptrace_scope=3..."
sysctl -w kernel.yama.ptrace_scope=3 || { echo "[!] sysctl write failed."; exit 1; }

cat > "$SYSCTL_CONF" <<EOF
# ssh-keysign-pwn (CVE-2026-46333) mitigation — $(date -u +%Y-%m-%dT%H:%M:%SZ)
# Scope 3: no process may ptrace any other. Use 2 if admins need debuggers.
kernel.yama.ptrace_scope = 3
EOF
echo "[+] Persistent config written to $SYSCTL_CONF"

ACTIVE_SCOPE=$(cat "$PTRACE_SCOPE_FILE")
[ "$ACTIVE_SCOPE" -ge 2 ] \
&& echo "[+] VERIFIED: ptrace_scope=$ACTIVE_SCOPE — exploit paths blocked." \
|| { echo "[!] FAIL: ptrace_scope=$ACTIVE_SCOPE."; exit 1; }

harden_nftables.sh — CVE-2026-23111

#!/bin/bash
# nf_tables Typo (CVE-2026-23111) Hardening Script
# Restricts unprivileged user namespaces to block the exploit reachability path.
# NOTE: the same gate also blocks CIFSwitch (CVE-2026-46243) and DirtyClone (CVE-2026-43503).

if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit 1
fi

echo "--- nf_tables Typo (CVE-2026-23111) Hardening ---"

SYSCTL_CONF="/etc/sysctl.d/99-nftables-userns.conf"

command -v podman &>/dev/null || systemctl is-active --quiet docker 2>/dev/null && \
echo "[!] WARNING: container runtime detected — rootless containers will break."

echo "[*] Setting user.max_user_namespaces=0..."
sysctl -w user.max_user_namespaces=0

HAVE_CLONE=false
if [ -f /proc/sys/kernel/unprivileged_userns_clone ]; then
sysctl -w kernel.unprivileged_userns_clone=0
HAVE_CLONE=true
fi

{
echo "# nf_tables Typo (CVE-2026-23111) mitigation — $(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo "# Also mitigates CIFSwitch (CVE-2026-46243) and DirtyClone (CVE-2026-43503)."
echo "user.max_user_namespaces = 0"
[ "$HAVE_CLONE" = true ] && echo "kernel.unprivileged_userns_clone = 0"
} > "$SYSCTL_CONF"
echo "[+] Persistent config written to $SYSCTL_CONF"

if ! runuser -u nobody -- unshare -U true 2>/dev/null; then
echo "[+] VERIFIED: unprivileged user namespace creation blocked."
else
echo "[!] FAIL: unprivileged userns still creatable — reboot may be required."
fi

harden_cifswitch.sh — CVE-2026-46243

#!/bin/bash
# CIFSwitch (CVE-2026-46243) Mitigation Script
# Advisory: https://heyitsas.im/posts/cifswitch/

if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit 1
fi

set -e
REQKEY_RULE="/etc/request-key.d/cifs.spnego.conf"
CIFS_BLACKLIST="/etc/modprobe.d/cifswitch.conf"
KEYCTL=$(command -v keyctl 2>/dev/null || echo "/usr/bin/keyctl")

echo "--- CIFSwitch (CVE-2026-46243) Mitigation ---"

command -v cifs.upcall &>/dev/null || echo "[+] cifs.upcall not found — cifs-utils not installed (primary mitigation)."

[ -f "$REQKEY_RULE" ] && [ ! -f "${REQKEY_RULE}.cifswitch.bak" ] && cp "$REQKEY_RULE" "${REQKEY_RULE}.cifswitch.bak"
cat > "$REQKEY_RULE" <<EOF
# CIFSwitch (CVE-2026-46243) mitigation — $(date -u +%Y-%m-%dT%H:%M:%SZ)
create cifs.spnego * * $KEYCTL negate %k 30 %S
EOF
echo "[+] Safe negate rule written to $REQKEY_RULE"

cat > "$CIFS_BLACKLIST" <<EOF
# CIFSwitch (CVE-2026-46243) mitigation — $(date -u +%Y-%m-%dT%H:%M:%SZ)
install cifs /bin/false
blacklist cifs
EOF
echo "[+] Module blacklist written to $CIFS_BLACKLIST"

if lsmod | grep -q '^cifs '; then
grep -q ' cifs ' /proc/mounts 2>/dev/null \
&& echo "[!] Active CIFS mounts — skipping unload." \
|| { modprobe -r cifs 2>/dev/null && echo "[+] cifs unloaded." || echo "[!] cifs unload failed — reboot to complete."; }
fi

command -v update-initramfs &>/dev/null && update-initramfs -u

harden_dirtyclone.sh — CVE-2026-43503

#!/bin/bash
# DirtyClone (CVE-2026-43503) Hardening Script
# CVSS 8.8 — highest severity in this set
# Mitigates cloned-packet page-cache LPE via module blacklist + userns restriction
# Patch: commit 48f6a5356a33, merged 2026-05-21
# Reference: https://thehackernews.com/2026/06/new-dirtyclone-linux-kernel-flaw-lets.html

if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit 1
fi

echo "--- DirtyClone (CVE-2026-43503) Hardening ---"

CONF_FILE="/etc/modprobe.d/dirtyclone.conf"
SYSCTL_CONF="/etc/sysctl.d/99-nftables-userns.conf"

# Check existing mitigations from earlier scripts in harden_all.sh
grep -qs 'install esp4 /bin/false' /etc/modprobe.d/*.conf 2>/dev/null \
&& echo "[+] esp4/esp6 already blacklisted by existing config." \
|| echo "[*] Writing esp4/esp6 module blacklist..."

cat > "$CONF_FILE" <<EOF
# DirtyClone (CVE-2026-43503) mitigation — $(date -u +%Y-%m-%dT%H:%M:%SZ)
# Independent layer: removal of fragnesia/dirtyfrag blacklists won't reopen this CVE.
install esp4 /bin/false
install esp6 /bin/false
install rxrpc /bin/false
EOF
echo "[+] Blacklist written to $CONF_FILE"

MODULES_IN_USE=false
lsmod | grep -qE "^(esp4|esp6|rxrpc)" && MODULES_IN_USE=true
if [ "$MODULES_IN_USE" = true ]; then
ip xfrm state 2>/dev/null | grep -q "proto esp" && echo "[!] Active IPsec SA detected."
echo "[!] Skipping module unload — active sessions. Schedule a reboot."
else
modprobe -r esp4 esp6 rxrpc 2>/dev/null
lsmod | grep -qE "^(esp4|esp6|rxrpc)" && echo "[!] Unload failed — reboot required." || echo "[+] Modules unloaded."
fi

# Apply userns restriction if not already in place from harden_nftables.sh
USERNS_VAL=$(sysctl -n user.max_user_namespaces 2>/dev/null || echo "unknown")
if [ "$USERNS_VAL" != "0" ]; then
echo "[*] Applying unprivileged user namespace restriction..."
sysctl -w user.max_user_namespaces=0
[ -f /proc/sys/kernel/unprivileged_userns_clone ] && sysctl -w kernel.unprivileged_userns_clone=0
[ ! -f "$SYSCTL_CONF" ] && {
echo "# DirtyClone (CVE-2026-43503) + nf_tables (CVE-2026-23111) mitigation" > "$SYSCTL_CONF"
echo "user.max_user_namespaces = 0" >> "$SYSCTL_CONF"
[ -f /proc/sys/kernel/unprivileged_userns_clone ] && echo "kernel.unprivileged_userns_clone = 0" >> "$SYSCTL_CONF"
echo "[+] Persistent sysctl config written to $SYSCTL_CONF"
} || echo "[*] $SYSCTL_CONF already in place (from harden_nftables.sh) — skipping."
else
echo "[+] user.max_user_namespaces already 0 — CAP_NET_ADMIN gate closed."
fi

echo "[*] Flushing page cache (host-wide — evicts any poisoned cached binaries)..."
sync; echo 1 > /proc/sys/vm/drop_caches
echo "[+] Page cache flushed."

command -v update-initramfs &>/dev/null && update-initramfs -u

echo "[*] Verification..."
# AF_RXRPC socket with IPPROTO_IP (protocol 2) — correct test for DirtyClone
if ! python3 -c "import socket; socket.socket(33, 2, 2)" 2>/dev/null; then
echo "[+] VERIFIED: kernel rejects AF_RXRPC socket (IPsec module path blocked)."
else
echo "[!] FAIL: AF_RXRPC socket still creatable — reboot may be required."
fi

if ! runuser -u nobody -- unshare -U true 2>/dev/null; then
echo "[+] VERIFIED: unprivileged user namespace creation blocked (CAP_NET_ADMIN gate closed)."
else
echo "[!] FAIL: unprivileged userns still creatable."
fi

echo ""
echo "--- Summary ---"
echo "Module blacklist: $CONF_FILE"
echo "ESP/RXRPC loaded: $(lsmod | grep -cE '^(esp4|esp6|rxrpc) ' || true) (0 = good)"
echo "Cache flush: done"
echo "max_user_namespaces: $(sysctl -n user.max_user_namespaces 2>/dev/null) (0 = hardened)"
echo "Upstream fix: commit 48f6a5356a33 (merged 2026-05-21)"

Priority 3 — Incident Response (If Exploitation Is Suspected)

For page-cache CVEs: do not invoke /usr/bin/su until the page cache has been cleared — doing so may spawn a root shell for any user. For ssh-keysign-pwn: rotate SSH host keys and audit /etc/shadow immediately. For CIFSwitch: audit /etc/sudoers.d for unexpected entries. For DirtyClone: the modification is host-wide and affects all processes — reboot immediately after flushing the cache.

For page-cache CVEs (CVE-2026-46300, CVE-2026-43284, CVE-2026-31431, CVE-2026-43503):

  1. Flush the page cache immediately:
sync && echo 1 > /proc/sys/vm/drop_caches
  1. Reboot the system as soon as operationally possible.
  2. Check for unexpected root-owned processes or modified sudoers/passwd entries.
  3. Review auth logs for privilege escalation events:
grep -E "su|sudo|root" /var/log/auth.log
journalctl _COMM=su --since "24 hours ago"

For ssh-keysign-pwn (CVE-2026-46333):

  1. Rotate all SSH host keys on affected systems:
rm /etc/ssh/ssh_host_*_key /etc/ssh/ssh_host_*_key.pub
ssh-keygen -A
systemctl restart sshd
  1. Audit /etc/shadow for unexpected password hash changes.
  2. Review auth logs for unexpected authentication events.

For nf_tables Typo and CIFSwitch (CVE-2026-23111, CVE-2026-46243):

  1. Audit /etc/sudoers.d/ and /etc/passwd for unexpected entries.
  2. Check for unexpected nsswitch.conf or libnss_*.so files in user-writable paths.
  3. Review logs for unprivileged unshare/nft activity.
  4. Apply the workaround or patch before bringing the system back into service.


Caveats

Fragnesia / Dirty Frag / DirtyClone (CVE-2026-46300, CVE-2026-43284, CVE-2026-43503)

Blacklisting esp4 and esp6 will break kernel-mode IPsec. This affects:

  • Site-to-site VPN tunnels using strongSwan or Libreswan in kernel ESP mode
  • Any IKEv1/IKEv2 configuration that offloads ESP processing to the kernel
Userspace VPN implementations (WireGuard, OpenVPN, Tailscale) are not affected.

If you are running a VPN gateway or any host with active IPsec SAs, review your network topology carefully and coordinate a maintenance window before applying the workaround. The hardening scripts will detect active IPsec SAs and skip the module unload step, but the blacklist will still be written — a subsequent reboot will drop those tunnels.

Copy-Fail (CVE-2026-31431)

Blacklisting af_alg removes AF_ALG socket access. This affects:

  • Some hardware crypto offload paths
  • cryptsetup benchmark and similar kernel crypto benchmarking tools
  • Certain OpenSSL engine configurations that use AF_ALG explicitly
Standard software-path TLS, LUKS/dm-crypt disk encryption, and most application crypto are unaffected.

ssh-keysign-pwn (CVE-2026-46333)

Setting ptrace_scope=3 disables all ptrace attach on the system. This affects:

  • gdb attaching to a running process
  • strace -p <pid> and similar diagnostic tools
  • Any tooling that uses PTRACE_ATTACH or pidfd_getfd on a live process
Use ptrace_scope=2 instead if administrator-level debugger access is needed. Both values block all known public PoCs.

Note that ptrace_scope is a runtime change — it takes effect immediately without a reboot and does not interrupt any ptrace sessions already in progress.

nf_tables Typo / CIFSwitch / DirtyClone (CVE-2026-23111, CVE-2026-46243, CVE-2026-43503)

Setting user.max_user_namespaces=0 disables unprivileged user namespace creation. This affects:

  • Rootless containers (Podman, rootless Docker, unprivileged LXC)
  • Sandboxing tools that rely on user namespaces (Flatpak, Bubblewrap, some browser sandboxes)

The firewall stack itself is unaffected — nf_tables continues to function normally. Only unprivileged namespace creation is blocked. One sysctl covers three CVEs.

CIFSwitch additionally overrides the cifs.spnego request-key rule with a safe negate and blacklists the cifs module. On diskless ggRock boot hosts these are typically no-ops since cifs-utils is usually not installed.


Verification

After applying the workaround, confirm the following on each system:

# No vulnerable modules should be loaded
lsmod | grep -E "esp4|esp6|rxrpc|algif_aead|af_alg|cifs"

# Socket creation should be rejected (Fragnesia/DirtyFrag)
python3 -c "import socket; socket.socket(33, 2, 0)"

# Socket creation should be rejected (Copy-Fail)
python3 -c "import socket; socket.socket(38, 5, 0)"

# Socket creation should be rejected (DirtyClone — note protocol 2, not 0)
python3 -c "import socket; socket.socket(33, 2, 2)"

# ptrace_scope should be 2 or 3
cat /proc/sys/kernel/yama/ptrace_scope

# Unprivileged user namespaces should be disabled (returns non-zero)
runuser -u nobody -- unshare -U true; echo "exit: $?"

# cifs.spnego rule should reference keyctl negate, not cifs.upcall
cat /etc/request-key.d/cifs.spnego.conf

All Python socket commands above should raise OSError: [Errno 97] Address family not supported by protocol — once the relevant module is blacklisted, the address family is unavailable. A clean exit (return code 0) means the module mitigation has not taken effect and a reboot is required. ptrace_scope should be ≥ 2. The unshare -U test should return a non-zero exit. The cifs.spnego rule should reference keyctl negate.


Frequently Asked Questions

Does this affect containers?

Containers share the host kernel. If the host kernel is vulnerable and a container runs with sufficient privileges to open the relevant socket families, it is in scope. Rootless containers and those with restricted seccomp/AppArmor profiles that block socket(AF_RXRPC, ...) and socket(AF_ALG, ...) have a reduced attack surface. CVE-2026-46333, CVE-2026-23111, CVE-2026-46243, and CVE-2026-43503 all carry container-escape potential. DirtyClone is particularly notable: page cache modifications made inside a namespace affect every process on the host machine.

Does this affect read-only root filesystems?

For the page-cache CVEs (including DirtyClone), the exploit targets the page cache, not the filesystem. A read-only root filesystem does not prevent the attack. For CVE-2026-46333, a read-only filesystem is irrelevant — the exploit reads in-memory file descriptors, not on-disk files. CVE-2026-46243 writes to sudoers.d via NSS inside the root helper, so a writable /etc is part of its chain.

Do I need to apply all seven scripts?

If you are patching promptly, one patched kernel covers all seven. If you are applying workarounds, run all seven (the master harden_all.sh does this in the correct order). Note that harden_nftables.sh closes the user-namespace gate relied upon by CIFSwitch and DirtyClone, and harden_fragnesia.sh blacklists the esp4/esp6 modules relied upon by DirtyClone — so ordering matters and the master script handles it correctly.

Can the workaround be reversed after patching?

Yes. After confirming you are running a patched kernel (see version table in Priority 1), remove the config files and revert the sysctls:

rm /etc/modprobe.d/disable-fragnesia.conf
rm /etc/modprobe.d/dirtyfrag.conf
rm /etc/modprobe.d/disable-copy-fail.conf
rm /etc/modprobe.d/cifswitch.conf
rm /etc/modprobe.d/dirtyclone.conf
rm /etc/sysctl.d/99-ssh-keysign-pwn.conf
rm /etc/sysctl.d/99-nftables-userns.conf
# Restore the original cifs.spnego rule if Kerberos CIFS is needed:
[ -f /etc/request-key.d/cifs.spnego.conf.cifswitch.bak ] && \
mv /etc/request-key.d/cifs.spnego.conf.cifswitch.bak /etc/request-key.d/cifs.spnego.conf
update-initramfs -u
sysctl -w kernel.yama.ptrace_scope=1
sysctl -w user.max_user_namespaces=15000
reboot


References

Updated on: 27/06/2026

Was this article helpful?

Share your feedback

Cancel

Thank you!