Leaving two people at the same typewriter and hoping the novel still makes sense
CVE-2025-39964 is a race condition (CWE-362) in the Linux kernel's af_alg_sendmsg function, which is the userspace-facing interface to the kernel cryptographic API via AF_ALG sockets. When two threads issue concurrent write() or sendmsg() calls on the same AF_ALG socket, data interleaves unpredictably and the internal socket state becomes inconsistent. The fix adds a ctx->write field enforcing exclusive write ownership. The vulnerability was introduced as far back as kernel 2.6.38 and affects virtually every stable branch up through 6.16.8, with fixes landing in 5.10.245, 5.15.194, 6.1.154, 6.6.108, 6.12.49, and 6.16.9.
The vendor's HIGH / 7.8 rating reflects the worst-case CVSS envelope: local access, low privileges, full CIA impact. That envelope is technically correct — a race-induced memory corruption in kernel space *can* theoretically escalate to root. However, the rating overweights theoretical ceiling and underweights practical friction. There is no public proof-of-concept, no observed exploitation, EPSS sits at the 0.3% mark, and race conditions in socket paths are notoriously difficult to weaponize reliably compared to straight-line logic bugs like the related Copy Fail (CVE-2026-31431) in the same AF_ALG subsystem. The vendor score deserves a downgrade to MEDIUM for real-world prioritization.
5 steps from start to impact.
Obtain local shell
- Local user account on target host
- Shell or code execution capability
- Requires prior compromise or insider access — filters out the vast majority of internet-facing threat actors
Open AF_ALG socket pair
socket(AF_ALG, SOCK_SEQPACKET, 0), binds it to a crypto algorithm (e.g., skcipher or aead), and calls accept() to get the operation file descriptor. AF_ALG sockets are available to unprivileged users on most default kernel configurations.- AF_ALG socket family enabled in kernel (CONFIG_CRYPTO_USER_API)
- Algorithm modules loaded or auto-loadable
- Some hardened distributions or container runtimes restrict AF_ALG via seccomp profiles — Docker's default seccomp profile does NOT block AF_ALG, but custom profiles may
- Kubernetes pod security standards at 'restricted' level may block raw socket creation
socket() syscalls with AF_ALG family (family=38) can flag unusual crypto socket creationTrigger concurrent writes
sendmsg() or write() on the same AF_ALG operation socket. The goal is to corrupt internal ctx state — specifically the scatter-gather list management — by interleaving partial writes. This requires precise timing and repeated attempts.- Multi-threaded execution capability
- Ability to win the race window before kernel scheduling preempts
- Race conditions in socket paths are timing-sensitive and unreliable — success rates on production workloads with scheduling jitter are low
- No known technique or tool automates reliable exploitation of this specific race
- Unlike Copy Fail (CVE-2026-31431), this is not a straight-line logic flaw — it requires genuine concurrency exploitation
Achieve kernel memory corruption
- Successful race condition trigger
- Heap layout favorable for exploitation (kernel heap feng shui)
- Modern kernels with SLAB_FREELIST_RANDOM, SLAB_FREELIST_HARDENED, CONFIG_INIT_ON_FREE_DEFAULT_ON significantly complicate heap shaping
- KASLR adds another layer of uncertainty for any ROP/JOP chain
- No public exploit demonstrates this pivot for CVE-2025-39964
Escalate to root
cred->uid) or hijacks control flow to disable SELinux/AppArmor and gain root. From root on the host, lateral movement to other hosts or container escape becomes possible.- Successful memory corruption primitive from step 4
- Bypass of kernel exploit mitigations (KASLR, SMEP, SMAP, CFI)
- Clang CFI and ARM64 PAC (on applicable architectures) make control-flow hijacking extremely difficult
- No demonstrated end-to-end chain exists for this CVE
The supporting signals.
| In-the-Wild Exploitation | None observed. Not listed in CISA KEV. No reports from threat intelligence vendors or incident response teams. |
|---|---|
| Proof-of-Concept | No public PoC exists. No exploit code on GitHub, Exploit-DB, or researcher blogs. The fix commit describes the theoretical impact but no reproduction steps beyond the bug description. |
| EPSS Score | 0.00323 — approximately 0.3rd percentile. Indicates the statistical model sees very low probability of exploitation in the next 30 days. |
| KEV Status | Not listed. No CISA KEV entry as of 2026-09-19. |
| CVSS Vector | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H — Local attack vector, low complexity (debatable for a race condition), low privileges required, no user interaction, unchanged scope, full CIA impact. |
| Affected Versions | Linux kernel 2.6.38 through 5.10.244, 5.11–5.15.193, 5.16–6.1.153, 6.2–6.6.107, 6.7–6.12.48, 6.13–6.16.8. Extremely wide range — virtually every supported kernel branch. |
| Fixed Versions | 5.10.245, 5.15.194, 6.1.154, 6.6.108, 6.12.49, 6.16.9. Distro backports: RHEL, Debian, Ubuntu, SUSE, Oracle Linux, Amazon Linux have all issued fixes. |
| Scanning/Exposure | Local-only vulnerability — not detectable via network scanning. Nessus plugin and Qualys QID available for authenticated local scans. 100% of unpatched Linux hosts are theoretically exposed but exploitation requires local access. |
| Disclosure Date | 2025-10-13 — publicly disclosed via kernel stable tree commits. |
| Reporter | Linux kernel developers via internal code review. No specific external researcher credited. |
noisgate verdict.
The single most decisive factor is the absence of any demonstrated exploit chain — this is a race condition with no public PoC, no in-the-wild exploitation, and a 0.3% EPSS score, making weaponization speculative rather than proven. While the kernel is a high-value component, the unproven exploitability of this specific race breaks the HIGH floor that would otherwise apply to a demonstrated kernel LPE.
Why this verdict
- No exploit exists: Zero public PoCs, no researcher demonstrations, no weaponized tooling. For a race condition disclosed 11 months ago, this silence is meaningful — compare to Copy Fail (CVE-2026-31431) in the same AF_ALG subsystem which had a 732-byte Python exploit within days.
- Race condition friction: Unlike straight-line logic bugs, this requires winning a timing race in kernel socket handling. Modern kernel scheduling, CPU frequency scaling, and workload jitter make reliable exploitation on production systems significantly harder than CVSS AC:L suggests.
- Local-only attack surface: AV:L means the attacker must already have a local shell. This prerequisite implies a prior compromise stage — the vulnerability is an escalation tool, not an entry point. The population of attackers who have local access but lack root is a subset of an already-compromised scenario.
- Role multiplier: The Linux kernel is canonically deployed in high-value roles (KVM hypervisors, container hosts, CI/CD runners, production database servers). An LPE on these targets has fleet-scale blast radius. However, because no exploit chain has been demonstrated for *this specific race condition*, the theoretical high-value-role outcome does not trigger the HIGH floor. If a PoC emerges, this verdict should be immediately re-evaluated to HIGH or CRITICAL.
- Kernel hardening mitigations: KASLR, SMEP/SMAP, SLAB_FREELIST_HARDENED, Clang CFI (on 6.x kernels), and CONFIG_INIT_ON_FREE all add friction layers that a theoretical exploit must bypass. These are active on most enterprise kernels.
Why not higher?
Upgrading to HIGH would require either a demonstrated exploit chain, active exploitation, or KEV listing. None of these exist. The 0.3% EPSS score and 11 months without a PoC for a publicly disclosed kernel race condition strongly suggest this is not practically exploitable with current techniques. If a PoC surfaces, upgrade immediately.
Why not lower?
Downgrading to LOW or IGNORE would undervalue the fact that this is a kernel-level memory corruption bug with full CIA impact *in theory*, affecting an enormous installed base across every major Linux distribution. The wide version range (2.6.38+) and the AF_ALG socket's default availability to unprivileged users mean the attack surface exists on nearly every Linux host. A future breakthrough in race condition exploitation could change the calculus overnight.
What to do — in priority order.
- Block AF_ALG sockets via seccomp — Apply a seccomp profile that denies
socket()calls withAF_ALG(family 38) to workloads that do not need userspace crypto API access. This eliminates the attack surface entirely for containerized and sandboxed workloads. Most applications use OpenSSL/libgcrypt in userspace and never touch AF_ALG. No mitigation SLA applies at MEDIUM — go straight to the 365-day remediation window. - Unload unused crypto API modules — If
algif_hash,algif_skcipher,algif_aead, andalgif_rngare not needed, blacklist them via/etc/modprobe.d/. This prevents the AF_ALG socket family from being usable even if the syscall is permitted. Verify withlsmod | grep algif. - Enable KASAN on staging/canary hosts — Kernel Address Sanitizer will detect the memory corruption caused by this race condition and panic the kernel before exploitation completes. Not suitable for production due to performance overhead, but useful for detection in pre-production environments.
- Audit AF_ALG socket creation with auditd — Add an audit rule:
auditctl -a always,exit -F arch=b64 -S socket -F a0=38 -k af_alg_access. This logs any process opening AF_ALG sockets, giving your SOC visibility into unexpected usage patterns.
- Network firewalls / WAF — This is a local-only vulnerability. No network-layer control can prevent exploitation since the attack never crosses a network boundary.
- SELinux / AppArmor in default policy — Default policies on RHEL and Ubuntu do not restrict AF_ALG socket creation for confined processes. Custom policy would be needed to block
socket(AF_ALG)specifically. - Container isolation alone — Docker's default seccomp profile does NOT block AF_ALG sockets. The kernel is shared between host and containers, so an exploit in a container compromises the host kernel.
Crowdsourced verification payload.
Run this script on each target Linux host as any user (no root required). Invoke with: bash check_cve_2025_39964.sh. It checks the running kernel version against known-fixed versions and reports VULNERABLE, PATCHED, or UNKNOWN.
#!/bin/bash\n# CVE-2025-39964 checker — af_alg concurrent write race condition\n# Run on target Linux host as any user\n\nKERNEL=$(uname -r)\nVERSION=$(echo \"$KERNEL\" | grep -oP '^[0-9]+\\.[0-9]+\\.[0-9]+')\nMAJOR=$(echo \"$VERSION\" | cut -d. -f1)\nMINOR=$(echo \"$VERSION\" | cut -d. -f2)\nPATCH=$(echo \"$VERSION\" | cut -d. -f3)\n\necho \"[*] Checking CVE-2025-39964 (af_alg race condition)\"\necho \"[*] Running kernel: $KERNEL\"\necho \"[*] Parsed version: $MAJOR.$MINOR.$PATCH\"\n\n# Fixed versions per stable branch:\n# 5.10.245, 5.15.194, 6.1.154, 6.6.108, 6.12.49, 6.16.9\n\nresult=\"UNKNOWN\"\n\nif [ \"$MAJOR\" -lt 2 ]; then\n result=\"PATCHED\" # Pre-2.6.38 not affected\nelif [ \"$MAJOR\" -eq 5 ] && [ \"$MINOR\" -eq 10 ]; then\n [ \"$PATCH\" -ge 245 ] && result=\"PATCHED\" || result=\"VULNERABLE\"\nelif [ \"$MAJOR\" -eq 5 ] && [ \"$MINOR\" -eq 15 ]; then\n [ \"$PATCH\" -ge 194 ] && result=\"PATCHED\" || result=\"VULNERABLE\"\nelif [ \"$MAJOR\" -eq 6 ] && [ \"$MINOR\" -eq 1 ]; then\n [ \"$PATCH\" -ge 154 ] && result=\"PATCHED\" || result=\"VULNERABLE\"\nelif [ \"$MAJOR\" -eq 6 ] && [ \"$MINOR\" -eq 6 ]; then\n [ \"$PATCH\" -ge 108 ] && result=\"PATCHED\" || result=\"VULNERABLE\"\nelif [ \"$MAJOR\" -eq 6 ] && [ \"$MINOR\" -eq 12 ]; then\n [ \"$PATCH\" -ge 49 ] && result=\"PATCHED\" || result=\"VULNERABLE\"\nelif [ \"$MAJOR\" -eq 6 ] && [ \"$MINOR\" -eq 16 ]; then\n [ \"$PATCH\" -ge 9 ] && result=\"PATCHED\" || result=\"VULNERABLE\"\nelif [ \"$MAJOR\" -ge 7 ]; then\n result=\"PATCHED\" # Future mainline includes fix\nelif [ \"$MAJOR\" -eq 5 ] && [ \"$MINOR\" -lt 10 ]; then\n result=\"VULNERABLE\" # 5.x before 5.10 stable branch\nelif [ \"$MAJOR\" -eq 5 ] && [ \"$MINOR\" -gt 10 ] && [ \"$MINOR\" -lt 15 ]; then\n result=\"VULNERABLE\" # 5.11-5.14 no stable fix\nelif [ \"$MAJOR\" -eq 6 ] && [ \"$MINOR\" -lt 1 ]; then\n result=\"VULNERABLE\"\nelif [ \"$MAJOR\" -eq 6 ] && [ \"$MINOR\" -gt 1 ] && [ \"$MINOR\" -lt 6 ]; then\n result=\"VULNERABLE\" # 6.2-6.5 no stable fix\nelif [ \"$MAJOR\" -eq 6 ] && [ \"$MINOR\" -gt 6 ] && [ \"$MINOR\" -lt 12 ]; then\n result=\"VULNERABLE\" # 6.7-6.11 no stable fix\nelif [ \"$MAJOR\" -eq 6 ] && [ \"$MINOR\" -gt 12 ] && [ \"$MINOR\" -lt 16 ]; then\n result=\"VULNERABLE\" # 6.13-6.15 no stable fix\nelse\n result=\"UNKNOWN\"\nfi\n\n# Check if AF_ALG is available (additional context)\nif [ -f /proc/config.gz ]; then\n if zcat /proc/config.gz 2>/dev/null | grep -q 'CONFIG_CRYPTO_USER_API=y'; then\n echo \"[*] AF_ALG: enabled (compiled in)\"\n elif zcat /proc/config.gz 2>/dev/null | grep -q 'CONFIG_CRYPTO_USER_API=m'; then\n echo \"[*] AF_ALG: module (may be loadable)\"\n else\n echo \"[*] AF_ALG: not configured (not exploitable)\"\n result=\"PATCHED\"\n fi\nelse\n echo \"[*] AF_ALG: config not available, assuming enabled\"\nfi\n\necho \"\"\necho \"=== RESULT: $result ===\"\n\nif [ \"$result\" = \"VULNERABLE\" ]; then\n exit 1\nelif [ \"$result\" = \"PATCHED\" ]; then\n exit 0\nelse\n exit 2\nfiIf you remember one thing.
algif_* kernel modules. Monitor for PoC emergence — if a working exploit drops, this verdict escalates to HIGH or CRITICAL immediately given the kernel's role as a high-value component, and the noisgate mitigation SLA would compress to 30 days (or hours if exploitation is confirmed in the wild).Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.