A dangerous gas leak — but only in the handful of kitchens that installed the experimental stove
CVE-2025-39682 is a use-after-free in the Linux kernel's kTLS (kernel TLS) receive path, specifically in tls_sw_recvmsg within net/tls/tls_sw.c. When a zero-length decrypted TLS record is pulled from rx_list, the type-change detection logic — which ensures each recvmsg() processes either contiguous DATA records or exactly one non-DATA record — is bypassed because the old code used copied (bytes already delivered) as a proxy for "did we commit a record type." A zero-length record means copied == 0, so the guard never fires, and a subsequent record of a different content type is processed in zero-copy mode when it shouldn't be. This queues the stream-parser's anchor SKB into rx_list with a corrupted refcount. On socket close, tls_sw_release_resources_rx frees the SKB, but the dangling frag_list pointer is still reachable — classic use-after-free. The bug was introduced in kernel 6.0 (commit 84c61fe1a75b) and affects every stable branch through 6.1.148, 6.6.102, 6.12.43, 6.16.3, and 6.17-rc1/rc2. STAR Labs SG published a full exploit chain demonstrating reliable local privilege escalation: UAF → heap spray → cross-cache attack → core_pattern overwrite → root shell. Fixes landed in 6.1.149, 6.6.103, 6.12.44, 6.16.4, and 6.17-rc3. Distro backports exist for Ubuntu (USN-7833 through USN-7940), SUSE, and Oracle Linux.
The vendor CVSS of 9.8 (AV:N/AC:L/PR:N/UI:N) is grossly misleading. It treats this as an unauthenticated, low-complexity, network-exploitable RCE — it is not. Red Hat independently scored it 7.0 (AV:N/AC:H) and NVD's alternate analysis scored 7.1 (AV:L/AC:L). The proven exploitation path is local privilege escalation, not remote code execution. Remote triggering (sending crafted TLS records to a kTLS-enabled server) can cause a kernel crash but achieving reliable RCE remotely via heap manipulation over the network is extremely high complexity. More importantly, kTLS is not enabled by default on any major distribution. The tls module must be explicitly loaded and an application (e.g., nginx with ssl_conf_command Options KTLS) must opt in. The population of exposed hosts is a small fraction of the Linux installed base. CISA added this to KEV on September 18, 2026 with a September 21 remediation deadline for FCEB agencies, confirming active exploitation — but exploitation observed in the wild appears to be post-access LPE, not internet-facing mass exploitation. The 9.8 paints a picture of Log4Shell-scale urgency; the reality is a serious but narrowly scoped kernel LPE affecting an opt-in subsystem.
5 steps from start to impact.
Attain local access to a kTLS-enabled host
tls kernel module is loaded and at least one process (e.g., nginx, HAProxy) has attached the TLS ULP to a TCP socket via setsockopt(SOL_TCP, TCP_ULP, "tls"). This is the fundamental prerequisite — without kTLS active, the vulnerable code path in tls_sw_recvmsg is unreachable. The attacker needs unprivileged local shell access (no root required).- Local shell access on the target host
- Kernel 6.0 through pre-fix version running
- kTLS module loaded (CONFIG_TLS=m and
modprobe tlsexecuted) - At least one process using TLS ULP sockets
- kTLS is compiled as a module but not loaded by default on RHEL, Ubuntu, Debian, SUSE, or Fedora
- Applications must explicitly opt into kTLS — nginx requires
ssl_conf_command Options KTLSin config - Estimated <5% of production Linux servers have the tls module loaded
- Requires prior initial access — phishing, stolen creds, compromised web app
lsmod | grep ^tls confirms module presence. Qualys QID and Tenable plugins exist for kernel version checks but do not verify kTLS runtime state.Create a TLS socket and craft the trigger sequence
copied == 0 condition that defeats the type-change guard.- Ability to create AF_INET sockets and call setsockopt for TLS ULP
- Knowledge of the cipher suite and keys (attacker controls both endpoints locally)
- Some hardened environments restrict unprivileged socket creation via seccomp or AppArmor
- Container runtimes may block
setsockoptfor TLS ULP unless explicitly allowed
setsockopt with TCP_ULP can flag ULP attachment by non-standard processes. STAR Labs published Suricata signatures for the TLS record pattern.Trigger the use-after-free via recvmsg()
read() to leave copied == 0 for the subsequent recvmsg() call. When recvmsg() processes the zero-length Handshake record from rx_list, the copied && control != TLS_RECORD_TYPE_DATA check evaluates to false (because copied == 0), so the loop continues to the next Application Data record. This record is processed in zero-copy mode (darg.zc == 1), and the stream-parser's anchor SKB (strp->anchor) is incorrectly queued into ctx->rx_list. The anchor's refcount is now corrupted.- Steps 1-2 completed successfully
- Kernel does not have the one-line fix applied (the
control &&vscopied &&swap)
- The fix is a single-line change — any distro kernel update from late September 2025 onward includes it
- KASAN-enabled kernels will detect the UAF immediately and panic rather than allow exploitation
CONFIG_KASAN=y) catches the UAF at kfree_skb_list_reason. Production kernels rarely run KASAN. No reliable network-side detection for the local path.Heap spray and cross-cache attack
frag_list pointer in the freed SKB is the exploitation primitive. The STAR Labs PoC uses heap spraying to reclaim the freed memory slab with attacker-controlled data, then performs a cross-cache attack to pivot from the network slab (skbuff_head_cache) into a more useful object (e.g., struct cred or pipe buffer). This gives the attacker a write-what-where primitive in kernel memory.- UAF successfully triggered in step 3
- Sufficient heap determinism (no heavy concurrent allocation pressure)
- Knowledge of kernel slab layout (KASLR bypasses may be needed for some targets)
- Modern kernels with SLAB_VIRTUAL or CONFIG_SLAB_FREELIST_RANDOM increase spray unreliability
- Cross-cache attacks are sensitive to system load — noisy production servers reduce success rate
- Multiple attempts may cause kernel panics, alerting monitoring
kdump) and unexpected reboots are the primary detection signal. EDR agents monitoring for anomalous core_pattern writes can catch the final stage.Overwrite core_pattern for root shell
/proc/sys/kernel/core_pattern to point to a script they control (e.g., |/tmp/pwn). They then trigger a segfault in any process, causing the kernel to execute their script as root. The STAR Labs PoC demonstrates reliable root shell acquisition through this technique. The attacker now has full control of the host.- Successful heap spray and cross-cache pivot from step 4
- Ability to write to
/tmpor another world-writable directory - A process that can be made to segfault (trivially achievable)
- Hosts with
fs.suid_dumpable=0and restrictedcore_pattern(read-only via sysctl) block this specific technique - Some container runtimes mount
/proc/sysread-only, preventingcore_patternabuse inside containers - SELinux in enforcing mode may block the core_pattern script execution
/proc/sys/kernel/core_pattern for unexpected changes. File integrity monitoring on the core_pattern sysctl value. EDR process-tree analysis will flag root shells spawned from core dump handlers.The supporting signals.
| In-the-Wild Exploitation | Confirmed. CISA added to KEV on 2026-09-18 citing "evidence of active exploitation." No specific threat actor or campaign attributed. Exploitation appears to be post-access LPE, not mass internet scanning. |
|---|---|
| Proof-of-Concept | Public and weaponized. STAR Labs SG published full advisory with C source PoC + Python TLS record generator (starlabs.sg/advisories/25/25-39682). GitHub repo suominen/CVE-2025-39682 also available. Demonstrates reliable unprivileged → root LPE. |
| EPSS | 0.012 (1.2% probability) — surprisingly low for a KEV-listed CVE. EPSS model likely hasn't fully weighted the recent KEV addition and public PoC. Expect this to climb significantly in the next model update. |
| KEV Status | Listed 2026-09-18. FCEB remediation deadline: 2026-09-21 (3 calendar days). BOD 26-04 applies. |
| CVSS Vector | Vendor (CVE.org): CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H = 9.8. Red Hat: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:H = 7.0. NVD alternate: AV:L/AC:L = 7.1. Red Hat and NVD alternate are materially more accurate — the proven chain is local, not unauthenticated remote RCE. |
| Affected Versions | Linux kernel 6.0 through 6.1.148, 6.2–6.6.102, 6.7–6.12.43, 6.13–6.16.3, 6.17-rc1/rc2. Introduced by commit 84c61fe1a75b4255. |
| Fixed Versions | Upstream: 6.1.149, 6.6.103, 6.12.44, 6.16.4, 6.17-rc3. Distro backports: Ubuntu USN-7833/7834/7835/7856/7887/7940, openSUSE-SU-2025:20081-1, multiple SUSE-SU-2025/2026 advisories, Oracle Linux. Red Hat: patches "under investigation" / "affected" — check RHSA for your specific RHEL version. |
| Scanning / Exposure | kTLS is not network-detectable from outside — there is no way to determine via Shodan/Censys/GreyNoise whether a remote host has the tls kernel module loaded. This is a local kernel subsystem, not an exposed service. Scanning must be agent-based (check kernel version + lsmod). |
| Disclosure Timeline | 2025-08-12: Reported to Linux kernel security team by STAR Labs SG. 2025-09-05: Patch released, CVE published. 2026-09-18: CISA KEV listing. 2026-09-21: FCEB deadline. |
| Researcher / Credit | Billy Jheng Bing-Jhong and Muhammad Alifa Ramdhan of STAR Labs SG Pte. Ltd. — a well-known offensive security research firm specializing in kernel and hypervisor exploitation. |
Why this verdict
- Vendor 9.8 is wrong on access vector. The CVE.org vector claims
AV:N/AC:L/PR:N/UI:N— unauthenticated network RCE with low complexity. The proven exploitation chain is local privilege escalation requiring unprivileged shell access. Remote trigger can cause DoS but reliable RCE over the network is extremely high complexity. Red Hat'sAV:N/AC:H(7.0) and NVD'sAV:L(7.1) are both more honest. Adjustment: baseline drops from 9.8 to ~7.0–7.5. - kTLS is opt-in, not default — population is narrow. The
tlskernel module is compiled as a loadable module (CONFIG_TLS=m) on modern distros but is not loaded by default on RHEL, Ubuntu, Debian, SUSE, or Fedora. Applications must explicitly callsetsockopt(TCP_ULP, "tls"). Real-world adoption is concentrated in high-performance TLS termination setups (nginx/HAProxy with kTLS tuning). Estimated <5% of production Linux hosts have the module loaded. This compresses the exposed population significantly versus a generic kernel vuln. - Local access prerequisite implies post-initial-access. The attacker must already have an unprivileged shell on the target. This means initial access (phishing, credential theft, web app compromise) has already succeeded. The vulnerability is a privilege escalation amplifier, not an entry point. This is a compounding downward factor.
- KEV listing and public PoC prevent going below HIGH. CISA confirmed active exploitation on 2026-09-18. STAR Labs published a reliable, weaponized PoC with heap spray and cross-cache techniques. The exploit is demonstrated, not theoretical. This puts a hard floor under the severity.
- Role multiplier: kTLS-enabled hosts are disproportionately high-value: they are production web servers, reverse proxies, load balancers, and Kubernetes ingress controllers running nginx/HAProxy with TLS termination. Root compromise on these hosts yields TLS private keys, access to backend networks, and potential pivot into the broader infrastructure. On a Kubernetes ingress controller, root → potential cluster compromise (access to kubelet creds, service account tokens). On a standalone nginx edge proxy, root → TLS key theft + internal network pivot. These outcomes (host-to-fleet escalation) are plausible for ≥1% of the affected installed base (i.e., of hosts running vulnerable kernels with kTLS loaded). This sets a floor of HIGH under the deployment-role analysis. However, kTLS is NOT canonically the role-defining software for these hosts (nginx is, the kernel is) — kTLS is a performance optimization, not an identity/trust/control-plane component — so the floor is HIGH, not CRITICAL.
Why not higher?
The proven chain requires local access (post-initial-access) AND the kTLS module to be loaded (opt-in, <5% of hosts). Remote code execution via network-sent TLS records is theoretical and extremely high complexity — no public PoC demonstrates it. The affected subsystem is an optional performance feature, not a default-on attack surface. These factors preclude CRITICAL even with KEV listing and active exploitation.
Why not lower?
CISA KEV listing with confirmed active exploitation and a public, weaponized LPE PoC from a top-tier research lab (STAR Labs SG) set a hard floor. The exploit reliably achieves unprivileged → root on any kTLS-enabled host with a vulnerable kernel. Hosts running kTLS are disproportionately high-value (TLS terminators, edge proxies, ingress controllers), and root compromise on them has outsized blast radius. MEDIUM would understate the risk for the segment of the fleet that actually runs kTLS.
What to do — in priority order.
- Blacklist the tls kernel module on hosts that don't need kTLS — Run
echo 'install tls /bin/false' > /etc/modprobe.d/disable-ktls.confandmodprobe -r tls(if currently loaded and no sockets are using it). This eliminates the attack surface entirely without a kernel update. Red Hat recommends this as their primary mitigation. Per the noisgate mitigation SLA for HIGH, deploy within 30 days — but given KEV active exploitation status, treat this as immediate (within hours). - Patch to a fixed kernel version — Update to 6.1.149+, 6.6.103+, 6.12.44+, 6.16.4+, or 6.17+ (upstream), or apply your distro's backported kernel package (Ubuntu USN-7833+, SUSE-SU-2025/2026, Oracle Linux). Per the noisgate remediation SLA for HIGH, apply the actual patch within 180 days — but given KEV listing, prioritize kTLS-enabled hosts for immediate patching.
- Audit which hosts have the tls module loaded — Run
lsmod | grep ^tlsacross your fleet via your configuration management tool (Ansible, Puppet, Salt). This gives you the actual scope of exposure. Hosts with the module loaded but not in a fixed kernel version are your priority-zero targets. - Restrict TLS ULP attachment via seccomp or AppArmor — If you run containerized workloads, ensure your seccomp profiles block
setsockoptwithTCP_ULPfor containers that don't need kTLS. This prevents exploitation from within containers even if the host kernel is vulnerable. - Monitor core_pattern for unauthorized changes — Set up file integrity monitoring (AIDE, osquery, or your EDR) to alert on changes to
/proc/sys/kernel/core_pattern. The public PoC's final exploitation stage writes to this sysctl. Detecting the write is a reliable indicator of active exploitation. - Enable KASAN on staging/canary hosts — Kernels compiled with
CONFIG_KASAN=ywill immediately detect the UAF and panic rather than allowing exploitation. Not viable for production due to performance overhead, but useful for canary detection in pre-production environments.
- Network firewalls / WAF — This is a local kernel vulnerability. No amount of network-level filtering prevents exploitation once an attacker has local access. The trigger is via local socket operations, not inbound network traffic.
- TLS inspection / SSL termination at the edge — The vulnerability is in the kernel's TLS processing, not in userspace OpenSSL/GnuTLS. Offloading TLS to a separate appliance doesn't help the host that has kTLS loaded.
- Disabling TLS 1.2 or specific cipher suites at the application level — The vulnerability is in the kernel ULP layer, below the application's TLS configuration. The PoC uses AES-CCM-128 but the root cause (zero-length record type-change bypass) is cipher-agnostic.
- ASLR/KASLR alone — While KASLR increases exploit complexity, the STAR Labs PoC demonstrates techniques to work around it. KASLR raises the bar but does not prevent exploitation.
Crowdsourced verification payload.
Run this script on each target Linux host as any user (root not required for version and module checks). Invoke with: bash check_cve_2025_39682.sh. It checks the running kernel version against known fixed versions and reports kTLS module status. No network access or special privileges needed.
#!/usr/bin/env bash
# check_cve_2025_39682.sh — CVE-2025-39682 kTLS UAF checker
# Usage: bash check_cve_2025_39682.sh
# Output: VULNERABLE / PATCHED / UNKNOWN
# Exit codes: 1=VULNERABLE, 0=PATCHED, 2=UNKNOWN
set -uo pipefail
KVER=$(uname -r)
# Extract numeric version components
VER_NUMS=$(echo "$KVER" | grep -oP '^[0-9]+\.[0-9]+\.[0-9]+')
if [[ -z "$VER_NUMS" ]]; then
echo "[!] Cannot parse kernel version: $KVER"
echo "UNKNOWN"
exit 2
fi
IFS='.' read -r MAJOR MINOR PATCH <<< "$VER_NUMS"
VULN="UNKNOWN"
# Vulnerability introduced in 6.0 (commit 84c61fe1a75b)
if [[ $MAJOR -lt 6 ]]; then
echo "[*] Kernel $KVER predates vulnerable code (introduced 6.0)."
echo "PATCHED"
exit 0
fi
if [[ $MAJOR -gt 6 ]]; then
echo "[*] Kernel $KVER is past all affected branches."
echo "PATCHED"
exit 0
fi
# Kernel is 6.x — check stable branch fix versions
# Fixed: 6.1.149, 6.6.103, 6.12.44, 6.16.4, 6.17+
case $MINOR in
0) VULN="VULNERABLE" ;; # 6.0.x — no stable fix, EOL
1) [[ $PATCH -ge 149 ]] && VULN="PATCHED" || VULN="VULNERABLE" ;;
[2-5]) VULN="VULNERABLE" ;; # 6.2–6.5 — EOL, no fix
6) [[ $PATCH -ge 103 ]] && VULN="PATCHED" || VULN="VULNERABLE" ;;
[7-9]|1[01]) VULN="VULNERABLE" ;; # 6.7–6.11 — EOL
12) [[ $PATCH -ge 44 ]] && VULN="PATCHED" || VULN="VULNERABLE" ;;
1[3-5]) VULN="VULNERABLE" ;; # 6.13–6.15 — EOL
16) [[ $PATCH -ge 4 ]] && VULN="PATCHED" || VULN="VULNERABLE" ;;
*) [[ $MINOR -ge 17 ]] && VULN="PATCHED" || VULN="UNKNOWN" ;;
esac
# Check kTLS module status
KTLS_LOADED="no"
KTLS_AVAIL="no"
if lsmod 2>/dev/null | grep -q '^tls '; then
KTLS_LOADED="yes"
KTLS_AVAIL="yes"
elif modinfo tls >/dev/null 2>&1; then
KTLS_AVAIL="yes"
fi
# Check for distro backport hints
BACKPORT_HINT=""
if command -v dpkg >/dev/null 2>&1; then
if dpkg -l linux-image-"$(uname -r)" 2>/dev/null | grep -q 'ii'; then
BACKPORT_HINT="Debian/Ubuntu detected. Run: apt changelog linux-image-$(uname -r) | grep -i CVE-2025-39682"
fi
elif command -v rpm >/dev/null 2>&1; then
if rpm -q kernel-"$(uname -r)" >/dev/null 2>&1; then
BACKPORT_HINT="RHEL/SUSE detected. Run: rpm -q --changelog kernel-$(uname -r) | grep -i CVE-2025-39682"
fi
fi
echo "=== CVE-2025-39682 Check ==="
echo "Kernel: $KVER"
echo "Parsed: $MAJOR.$MINOR.$PATCH"
echo "kTLS module: available=$KTLS_AVAIL loaded=$KTLS_LOADED"
echo "Version check: $VULN"
[[ -n "$BACKPORT_HINT" ]] && echo "Backport note: $BACKPORT_HINT"
echo "==========================="
if [[ "$VULN" == "VULNERABLE" ]]; then
if [[ "$KTLS_LOADED" == "yes" ]]; then
echo "[!!!] ACTIVELY EXPLOITABLE: Vulnerable kernel + kTLS loaded."
elif [[ "$KTLS_AVAIL" == "yes" ]]; then
echo "[!!] AT RISK: Vulnerable kernel, kTLS available but not loaded."
else
echo "[!] VULNERABLE kernel but kTLS module not available (low risk)."
fi
echo "VULNERABLE"
exit 1
elif [[ "$VULN" == "PATCHED" ]]; then
echo "PATCHED"
exit 0
else
echo "[?] Could not determine status. Check distro backport."
echo "UNKNOWN"
exit 2
fi- STAR Labs SG — Full Advisory with PoC
- CISA KEV Catalog — CVE-2025-39682 Addition
- The Hacker News — CISA Flags Three Linux Kernel Flaws
- Red Hat CVE Entry — CVSS 7.0 Assessment & Mitigation
- SecurityWeek — Organizations Warned of Exploited Kernel Vulns
- Ubuntu Security — CVE-2025-39682 Tracker
- GitHub PoC Repository — suominen/CVE-2025-39682
- F5/NGINX — kTLS Configuration and Requirements
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.