← Back to Feed CACHED · 2026-09-21 12:52:16 · CACHE_KEY CVE-2025-39682
CVE-2025-39682 · CWE-754 · Disclosed 2025-09-05

In the Linux kernel

ASSESSED — NOISGATE
Vendor
Reassessed
Verdict:
Do you agree?
01 · The Real Story

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.

"Vendor scored this as if every Linux box runs kTLS. Almost none do. HIGH for the few that opted in."
02 · The Attack Path

5 steps from start to impact.

STEP 01

Attain local access to a kTLS-enabled host

The attacker establishes a foothold on a Linux host running kernel 6.0+ where the 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).
Conditions required:
  • Local shell access on the target host
  • Kernel 6.0 through pre-fix version running
  • kTLS module loaded (CONFIG_TLS=m and modprobe tls executed)
  • At least one process using TLS ULP sockets
Where this breaks in practice:
  • 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 KTLS in config
  • Estimated <5% of production Linux servers have the tls module loaded
  • Requires prior initial access — phishing, stolen creds, compromised web app
Detection/coverage: Runtime check: lsmod | grep ^tls confirms module presence. Qualys QID and Tenable plugins exist for kernel version checks but do not verify kTLS runtime state.
STEP 02

Create a TLS socket and craft the trigger sequence

The attacker creates a TCP connection pair, attaches the TLS ULP, and negotiates TLS 1.2 with AES-CCM-128 (or another supported cipher). Using the STAR Labs PoC methodology, they send a sequence: (1) a normal Application Data record with payload, (2) a zero-length Handshake record (type 0x16), and (3) a second Application Data record. The zero-length record is the key — it causes the copied == 0 condition that defeats the type-change guard.
Conditions required:
  • Ability to create AF_INET sockets and call setsockopt for TLS ULP
  • Knowledge of the cipher suite and keys (attacker controls both endpoints locally)
Where this breaks in practice:
  • Some hardened environments restrict unprivileged socket creation via seccomp or AppArmor
  • Container runtimes may block setsockopt for TLS ULP unless explicitly allowed
Detection/coverage: Audit rules on setsockopt with TCP_ULP can flag ULP attachment by non-standard processes. STAR Labs published Suricata signatures for the TLS record pattern.
STEP 03

Trigger the use-after-free via recvmsg()

The attacker partially reads the first record via 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.
Conditions required:
  • Steps 1-2 completed successfully
  • Kernel does not have the one-line fix applied (the control && vs copied && swap)
Where this breaks in practice:
  • 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
Detection/coverage: KASAN (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.
STEP 04

Heap spray and cross-cache attack

After triggering the UAF, the attacker closes the socket. The dangling 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.
Conditions required:
  • 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)
Where this breaks in practice:
  • 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
Detection/coverage: Kernel crash dumps (kdump) and unexpected reboots are the primary detection signal. EDR agents monitoring for anomalous core_pattern writes can catch the final stage.
STEP 05

Overwrite core_pattern for root shell

With the kernel write primitive, the attacker overwrites /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.
Conditions required:
  • Successful heap spray and cross-cache pivot from step 4
  • Ability to write to /tmp or another world-writable directory
  • A process that can be made to segfault (trivially achievable)
Where this breaks in practice:
  • Hosts with fs.suid_dumpable=0 and restricted core_pattern (read-only via sysctl) block this specific technique
  • Some container runtimes mount /proc/sys read-only, preventing core_pattern abuse inside containers
  • SELinux in enforcing mode may block the core_pattern script execution
Detection/coverage: Monitor /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.
03 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationConfirmed. 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-ConceptPublic 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.
EPSS0.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 StatusListed 2026-09-18. FCEB remediation deadline: 2026-09-21 (3 calendar days). BOD 26-04 applies.
CVSS VectorVendor (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 VersionsLinux 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 VersionsUpstream: 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 / ExposurekTLS 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 Timeline2025-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 / CreditBilly 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.
04 · The Call

Final Verdict
DOWNGRADED to HIGH (7.5/10)

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's AV:N/AC:H (7.0) and NVD's AV: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 tls kernel 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 call setsockopt(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.

05 · Compensating Control

What to do — in priority order.

  1. Blacklist the tls kernel module on hosts that don't need kTLS — Run echo 'install tls /bin/false' > /etc/modprobe.d/disable-ktls.conf and modprobe -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).
  2. 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.
  3. Audit which hosts have the tls module loaded — Run lsmod | grep ^tls across 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.
  4. Restrict TLS ULP attachment via seccomp or AppArmor — If you run containerized workloads, ensure your seccomp profiles block setsockopt with TCP_ULP for containers that don't need kTLS. This prevents exploitation from within containers even if the host kernel is vulnerable.
  5. 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.
  6. Enable KASAN on staging/canary hosts — Kernels compiled with CONFIG_KASAN=y will 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.
What doesn't work
  • 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.
06 · Verification

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.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/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
07 · Sources

Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.