Leaving the front door unlocked for 14 years because nobody tried the handle until now
CVE-2025-39964 is a race condition in the Linux kernel's AF_ALG socket interface — the userspace API for kernel cryptographic operations — present since kernel 2.6.38 (March 2011). When two threads issue concurrent sendmsg() calls on the same AF_ALG socket, the kernel releases the socket lock while waiting for writable buffer space. A second writer can then modify the shared scatter-gather list state, leaving ctx->merge set to true while cur equals zero. The subsequent write dereferences sg[-1], accessing heap memory *before* the intended array. Researchers Muhammad Alifa Ramdhan and Bing-Jhong Billy Jheng of STAR Labs chained this out-of-bounds access into a usercopy oracle, then an arbitrary kernel write primitive, then overwrote core_pattern to obtain root — and demonstrated container escape since containers share the host kernel. Affected versions span 2.6.38 through unpatched builds of every active stable branch. Fixed upstream in commit 1b34cbbf4f01 (September 2025); stable backports landed in 5.10.246, 5.15.195, 6.1.155, 6.6.109, 6.12.50, and 6.16.10.
The vendor CVSS of 7.8 HIGH (AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H) is technically accurate for a standard local privilege escalation, but it *under-weights* the real-world blast radius. The CVSS vector's S:U (Scope: Unchanged) ignores the proven container-escape path — the scope absolutely changes when a compromised pod pivots to the host node. CISA added CVE-2025-39964 to the KEV catalog on 2026-09-18 citing active exploitation. Public exploit code exists on GitHub (n1k0oowang/CVE-2025-39964_EXP). The AF_ALG module is compiled into most enterprise kernels (CONFIG_CRYPTO_USER_API=y), so the common advice to blacklist the module does not work. Red Hat explicitly confirmed no viable mitigation short of patching. When you combine proven exploitation, public weaponized code, container escape, OT/ICS exposure (Siemens SIMATIC S7-1500 MFP firmware runs a Linux subsystem with this flaw), and the impossibility of mitigation via module blacklist, the vendor's HIGH underestimates the operational reality.
6 steps from start to impact.
Obtain unprivileged local access
- Local code execution as any unprivileged user
- Target kernel is in the affected range (2.6.38 – unpatched)
- Requires prior initial access — not remotely exploitable without a chained entry vector
- Hardened SSH configurations, MFA, and EDR may prevent or detect the initial foothold
Open an AF_ALG socket and race two writers
socket(AF_ALG, SOCK_SEQPACKET, 0), binds it to a hash or skcipher algorithm, then spawns two threads issuing sendmsg() concurrently. The kernel releases the socket lock while waiting for buffer space, allowing the second writer to corrupt the scatter-gather list state. The exploit targets the window where ctx->merge is true but cur is zero.- AF_ALG socket family available (compiled in or loadable)
- Kernel does not carry the fix commit
1b34cbbf4f01
- AF_ALG is compiled directly into RHEL/CentOS/Ubuntu enterprise kernels — cannot be blacklisted
- Race window is narrow but the STAR Labs exploit demonstrated reliable winning within seconds
- Some container runtimes with restrictive seccomp profiles (e.g., default Docker profile) may block
socket(AF_ALG, …)— but Kubernetes pods withsecurityContext.seccompProfile: Unconfinedor custom profiles allow it
auditctl -a always,exit -F arch=b64 -S socket -F a0=38) can flag AF_ALG socket creation; Falco rules can detect socket() with AF_ALG domain.Trigger out-of-bounds heap read via sg[-1]
sg[-1], reading metadata from the heap object immediately preceding the scatter-gather array. The attacker crafts heap layout (via controlled allocations) so that this preceding object contains attacker-influenced data. This provides a usercopy oracle — the ability to read arbitrary kernel memory by observing what the kernel copies back to userspace.- Successful race condition (Step 2)
- Heap spray to position controlled data before the sg array
- Kernel heap randomization (SLAB_FREELIST_RANDOM, SLAB_FREELIST_HARDENED) makes layout control harder but not impossible
- KASLR must be bypassed — the oracle itself provides the leak
Achieve arbitrary kernel write primitive
- Successful heap oracle (Step 3)
- Knowledge of target kernel's symbol offsets (public for distro kernels)
- Hardcoded offsets in public PoC limit portability — attacker must adapt to target kernel version
- CONFIG_CFI_CLANG (Control Flow Integrity) on newer kernels can disrupt ROP/JOP chains
Overwrite core_pattern → root shell
|/tmp/payload) into /proc/sys/kernel/core_pattern, then triggers a segfault in a child process. The kernel executes the payload as root during core dump handling. The STAR Labs exploit demonstrated this path reliably.- Arbitrary kernel write (Step 4)
- Writable location for payload binary (typically /tmp)
- Systems with
fs.suid_dumpable=0and restricted core dump settings reduce attack surface but do not prevent the core_pattern overwrite via kernel write - AppArmor/SELinux *may* block execution of the payload if the policy is restrictive enough — but the kernel write can also disable LSM enforcement
/proc/sys/kernel/core_pattern changes; auditd rule on sysctl writes.Container escape to host (if containerized)
- Target process is inside a container (Docker, containerd, CRI-O)
- Container runtime does not block AF_ALG via seccomp
- Default Docker seccomp profile *does* block AF_ALG socket creation — but many K8s deployments run with relaxed or no seccomp
- gVisor or Kata Containers (VM-based isolation) prevent host kernel exploitation entirely
socket(AF_ALG, …). Ensure all Kubernetes pods run with RuntimeDefault or a custom profile that denies AF_ALG socket creation (family 38). This breaks Step 2 of the attack chain inside containers. Does NOT protect host-level processes. Deploy within 3 days on all container runtimes.socket() calls with AF_ALG (family=38). This provides detection-in-depth: any process opening an AF_ALG socket on a production server is anomalous in most workloads. Alert and investigate immediately. Deploy within 3 days.- Blacklisting the af_alg kernel module — AF_ALG is compiled directly into enterprise kernels (
CONFIG_CRYPTO_USER_API=y) on RHEL, CentOS, Ubuntu, Debian, and SUSE.modprobe -rand blacklist entries have no effect. Red Hat explicitly confirmed this. - Disabling core dumps (
ulimit -c 0) — While the public PoC usescore_patternoverwrite, the arbitrary kernel write primitive can target any kernel data structure. Disabling core dumps blocks one payload delivery method but not the underlying write-what-where capability. - Namespace isolation alone — User namespaces do not prevent AF_ALG socket access in most configurations. The vulnerability operates at the kernel level, below namespace boundaries. Only VM-based isolation (gVisor, Kata Containers) provides a real boundary.
The supporting signals.
| In-the-Wild Exploitation | Confirmed. CISA added CVE-2025-39964 to the KEV catalog on 2026-09-18 citing evidence of active exploitation. Ransomware usage listed as *Unknown*. |
|---|---|
| Proof-of-Concept | Public. n1k0oowang/CVE-2025-39964_EXP on GitHub contains exploit.c with a compiled LPE. STAR Labs researchers (Muhammad Alifa Ramdhan, Bing-Jhong Billy Jheng) demonstrated a full root + container escape chain via Google's kernelCTF program ($113,337 bounty). suominen/CVE-2025-39964 tracks distro patch status. |
| EPSS | 0.01276 (user-supplied). This is a modest probability reflecting the local-access prerequisite, but EPSS historically lags KEV listings — exploitation is confirmed regardless of the score. |
| CVSS Vector | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H → 7.8 HIGH. The S:U (Scope Unchanged) is arguably wrong given proven container escape. Red Hat scored it 7.3 HIGH under their own assessment. |
| Affected Versions | Linux kernel 2.6.38 (March 2011) through all unpatched branches. That is a 14-year window. Siemens SIMATIC S7-1500 CPU 1518(F)-4 PN/DP MFP firmware V3.1.6 also affected (runs Linux subsystem). |
| Fixed Versions | Upstream commit 1b34cbbf4f01 (2025-09-16). Stable backports: 5.10.246, 5.15.195, 6.1.155, 6.6.109, 6.12.50, 6.16.10. Debian: bookworm 6.1.187-1, trixie 6.12.111-1. RHEL: errata shipped 2026-09-22 to 2026-09-24 across RHEL 7 ELS–10. |
| KEV Dates | Added: 2026-09-18. Required action (BOD 26-04): 2026-09-21. Three-day remediation window for FCEB agencies. |
| Researcher / Discovery | Muhammad Alifa Ramdhan and Bing-Jhong Billy Jheng of STAR Labs, via Google kernelCTF. Bounty: $113,337. |
| Scanning / Exposure | AF_ALG is compiled into enterprise kernels (CONFIG_CRYPTO_USER_API=y) — not a loadable module. Red Hat confirmed blacklisting is impossible. Every unpatched Linux host in your fleet is exposed if an attacker achieves local access. |
| OT / ICS Impact | CISA issued ICS advisory ICSA-26-209-04 for Siemens SIMATIC S7-1500 CPU 1518(F)-4 PN/DP MFP. Siemens is preparing fixes; no patch available yet for the PLC firmware. |
Sources.
Why this verdict
- Active exploitation confirmed. CISA KEV listing on 2026-09-18 with evidence of in-the-wild use overrides any friction-based downgrade. When exploitation is confirmed, theoretical barriers are moot — someone is already landing this chain.
- Public weaponized exploit code. The n1k0oowang GitHub repo provides compiled exploit code, and STAR Labs published detailed research. The bar for attacker adoption is low — compile, adapt offsets for target distro kernel, run.
- Container escape transforms blast radius from host to fleet. The CVSS vector's
S:Uis incorrect for containerized environments. A compromised pod → host root → node takeover → lateral to other pods/nodes. In Kubernetes clusters, one exploited container can cascade to full cluster compromise. - Role multiplier: The affected component is the Linux kernel itself. 100% of Linux hosts run it. High-value roles include: (1) Kubernetes nodes — container escape gives fleet-scale blast radius, chain succeeds, outcome is cluster takeover; (2) KVM hypervisors — guest-to-host escape path if guest has AF_ALG access, outcome is hypervisor compromise; (3) CI/CD runners — any build job can escalate, outcome is supply-chain pivot; (4) OT/ICS controllers — Siemens SIMATIC S7-1500 MFP runs affected Linux kernel, outcome is operational/safety impact. The kernel is canonically a high-value-role component (≥10% of installs ARE the high-value role), setting a CRITICAL floor.
- No viable mitigation short of patching. AF_ALG is compiled in, not a module. Red Hat explicitly stated no mitigation meets their criteria. You cannot reduce exposure without patching the kernel or deploying a livepatch.
- 14-year exposure window. Every kernel since 2.6.38 (2011) is affected. The installed base of vulnerable hosts across enterprise Linux fleets is effectively universal for anyone not running the September 2025+ stable backports.
Why not higher?
A 9.0 is already near the top of the scale. A 10.0 would require unauthenticated remote exploitation without user interaction. This vulnerability requires local access (AV:L) — even in containerized environments, the attacker must first achieve code execution inside a container. The race condition, while reliable, is not instant and requires a compiled exploit adapted to the target kernel version's symbol offsets.
Why not lower?
Despite the local-access prerequisite, downgrading below CRITICAL would ignore three hard facts: (1) CISA has confirmed active exploitation — the chain works in production, (2) the affected component is the kernel itself with no scope boundary protecting the host from container compromise, and (3) there is no compensating control that reduces exposure without a kernel update. A HIGH rating would imply defenders have 30 days for mitigation, which contradicts the KEV's 3-day action window and the reality of confirmed exploitation.
Crowdsourced verification payload.
Run this script on each target Linux host as root (or with sudo). It checks whether the running kernel version is in the patched range. Invoke with: sudo bash check_cve_2025_39964.sh. No arguments required. Returns exit code 0 for PATCHED, 1 for VULNERABLE, 2 for UNKNOWN.
#!/bin/bash
# CVE-2025-39964 Checker — AF_ALG concurrent-write race condition
# Checks running kernel version against known-fixed stable branches.
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -euo pipefail
KERNEL=$(uname -r)
VERSION=$(echo "$KERNEL" | grep -oP '^[0-9]+\.[0-9]+\.[0-9]+')
if [ -z "$VERSION" ]; then
echo "UNKNOWN — could not parse kernel version from: $KERNEL"
exit 2
fi
MAJOR=$(echo "$VERSION" | cut -d. -f1)
MINOR=$(echo "$VERSION" | cut -d. -f2)
PATCH=$(echo "$VERSION" | cut -d. -f3)
# version_gte: returns 0 if $1.$2.$3 >= $4.$5.$6
version_gte() {
local a1=$1 a2=$2 a3=$3 b1=$4 b2=$5 b3=$6
if (( a1 > b1 )); then return 0; fi
if (( a1 < b1 )); then return 1; fi
if (( a2 > b2 )); then return 0; fi
if (( a2 < b2 )); then return 1; fi
if (( a3 >= b3 )); then return 0; fi
return 1
}
echo "Kernel: $KERNEL (parsed: $MAJOR.$MINOR.$PATCH)"
echo "CVE: CVE-2025-39964 — AF_ALG concurrent-write race"
echo "Fix commit: 1b34cbbf4f01 (upstream 2025-09-16)"
echo "---"
# Fixed stable versions:
# 5.10.246, 5.15.195, 6.1.155, 6.6.109, 6.12.50, 6.16.10
# Kernels < 2.6.38 are NOT affected (feature did not exist).
# Kernels >= 6.17-rc7 / 6.17+ carry the fix.
if version_gte $MAJOR $MINOR $PATCH 6 17 0; then
echo "PATCHED — kernel $VERSION is >= 6.17 (fix merged in 6.17-rc7)"
exit 0
elif (( MAJOR == 6 && MINOR == 16 )); then
if version_gte $MAJOR $MINOR $PATCH 6 16 10; then
echo "PATCHED — kernel $VERSION is >= 6.16.10"
exit 0
fi
elif (( MAJOR == 6 && MINOR == 12 )); then
if version_gte $MAJOR $MINOR $PATCH 6 12 50; then
echo "PATCHED — kernel $VERSION is >= 6.12.50"
exit 0
fi
elif (( MAJOR == 6 && MINOR == 6 )); then
if version_gte $MAJOR $MINOR $PATCH 6 6 109; then
echo "PATCHED — kernel $VERSION is >= 6.6.109"
exit 0
fi
elif (( MAJOR == 6 && MINOR == 1 )); then
if version_gte $MAJOR $MINOR $PATCH 6 1 155; then
echo "PATCHED — kernel $VERSION is >= 6.1.155"
exit 0
fi
elif (( MAJOR == 5 && MINOR == 15 )); then
if version_gte $MAJOR $MINOR $PATCH 5 15 195; then
echo "PATCHED — kernel $VERSION is >= 5.15.195"
exit 0
fi
elif (( MAJOR == 5 && MINOR == 10 )); then
if version_gte $MAJOR $MINOR $PATCH 5 10 246; then
echo "PATCHED — kernel $VERSION is >= 5.10.246"
exit 0
fi
fi
# Check if kernel predates the vulnerable code (< 2.6.38)
if (( MAJOR < 2 )) || { (( MAJOR == 2 )) && (( MINOR < 6 )); } || \
{ (( MAJOR == 2 )) && (( MINOR == 6 )) && (( PATCH < 38 )); }; then
echo "PATCHED — kernel $VERSION predates AF_ALG (introduced in 2.6.38)"
exit 0
fi
# Check for distro-patched kernels (RHEL, Debian, Ubuntu often backport)
# Look for the actual fix in the kernel config/source
if [ -f /boot/config-$(uname -r) ]; then
# If CONFIG_CRYPTO_USER_API is not set, AF_ALG is not available
if ! grep -q 'CONFIG_CRYPTO_USER_API=y' /boot/config-$(uname -r) 2>/dev/null && \
! grep -q 'CONFIG_CRYPTO_USER_API=m' /boot/config-$(uname -r) 2>/dev/null; then
echo "PATCHED — AF_ALG (CONFIG_CRYPTO_USER_API) is not enabled in this kernel"
exit 0
fi
fi
# Check for distro errata markers
if command -v rpm &>/dev/null; then
RPM_KERNEL=$(rpm -q kernel-$(uname -r) 2>/dev/null || rpm -q kernel-core-$(uname -r) 2>/dev/null || true)
if [ -n "$RPM_KERNEL" ]; then
echo "NOTE: RPM kernel package: $RPM_KERNEL"
echo "Check vendor errata (RHSA/ELSA/ALSA) for CVE-2025-39964 fix status."
fi
elif command -v dpkg &>/dev/null; then
DEB_KERNEL=$(dpkg -l 'linux-image-*' 2>/dev/null | grep "$(uname -r)" | awk '{print $2, $3}' || true)
if [ -n "$DEB_KERNEL" ]; then
echo "NOTE: Debian/Ubuntu kernel: $DEB_KERNEL"
echo "Check DSA-6053-1 / DLA-4379-1 / USN advisories for fix status."
fi
fi
echo "VULNERABLE — kernel $VERSION does not match any known-fixed stable version"
echo "Action: Apply vendor kernel update or livepatch immediately (KEV-listed, active exploitation)."
exit 1