Skip to content

CVE-2025-39682: Linux Kernel kTLS Receive Path Zero-Length Record Use-After-Free Privilege Escalation

HERMES

HERMES THREAT SCORE & KERNEL PRIVILEGE ESCALATION

Target: Linux Kernel Core Subsystem β€” net/tls/ (Kernel TLS Software Receive Path)
Confidence: 99%
94 / 100
CRITICAL

Measures real-world operational relevance, exploit weaponization, and active threat posture.

Dimension Breakdown
Exploitability 19 / 20
Threat Activity 20 / 20
Weaponization 20 / 20
Exposure 17 / 20
Prevalence 20 / 20
Impact 19 / 20
Exploit Maturity 20 / 20
Attack Chain Potential 19 / 20
βš–οΈ Divergence & Operational Rationale

CVSS v3.1 rates CVE-2025-39682 at 7.8 High (CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H) due to the local access vector requirement (AV:L). However, Hermes Threat Score evaluates it at 94 (CRITICAL / KEV Tier-1) following confirmed active in-the-wild exploitation cataloged by CISA on September 18, 2026. In cloud environments, shared Kubernetes worker nodes, and enterprise web servers, kTLS is widely enabled for hardware and software crypto offload. Attackers chaining web application compromise or container escapes leverage this flaw for deterministic, local root escalation across enterprise Linux distributions.

πŸ•ΈοΈ Connected Knowledge Graph & Provenance

CVE-2025-39682: Linux Kernel kTLS Receive Path Zero-Length Record Use-After-Free Privilege EscalationVULNERABILITY

Connected Nodes: 1
Active Relationships (Outgoing)
→ affectsPRODUCTLinux Kernel Core
98% VERY_HIGH

Software platform affected by security vulnerabilities and agentic attack patterns.

πŸ” Why is this related? (Evidence & Provenance)

“Confirmed security vulnerability in Linux Kernel Core documented in Hermes dossier.”

Supporting Verified Evidence:

kTLS is initialized on standard TCP sockets using the TCP_ULP (Upper Layer Protocol) socket option:

int sock = socket(AF_INET, SOCK_STREAM, 0);
connect(sock, (struct sockaddr *)&target, sizeof(target));
// Enable kernel TLS Upper Layer Protocol
setsockopt(sock, SOL_TCP, TCP_ULP, "tls", sizeof("tls"));
// Configure symmetric crypto parameters for RX
setsockopt(sock, SOL_TLS, TLS_RX, &crypto_info, sizeof(crypto_info));

Once enabled, all incoming ciphertext is decrypted by the kernel’s asynchronous or synchronous crypto drivers, assembling plaintext into socket buffers placed on tls_sw_context_rx->rx_list.

ParameterTechnical DetailOperational Impact
CVE IdentifierCVE-2025-39682CISA KEV Catalog Entry 2026-09-18
Vulnerability ClassUse-After-Free (CWE-416) & Unusual Condition Handling (CWE-754)Local Privilege Escalation (LPE) to root
Vulnerable Componentnet/tls/tls_sw.c (tls_sw_recvmsg)Kernel in-tree TLS networking subsystem
Trigger VectorsLocal unprivileged invocation of recvmsg() on crafted kTLS TCP socketLocal shell, container, or web application RCE
Authentication RequiredLow (PR:L) / Local unprivileged shell or container UIDLocal execution without root or special capabilities
ImpactComplete Kernel Ring-0 Execution / Credential HarvestingFull operating system root takeover
Affected Versions6.0–6.1.148, 6.2–6.6.102, 6.7–6.12.43, 6.13–6.16.3, 6.17-rc1..rc2Linux distributions enabling CONFIG_TLS
Remediated ReleaseMaintenance kernels 6.1.149, 6.6.103, 6.12.44, 6.16.4, 6.17Distribution vendor backports (RHEL, Ubuntu, Debian)

The core vulnerability resides in the loop inside tls_sw_recvmsg() that iterates through the socket’s receive queue (ctx->rx_list) to service a user’s recvmsg() buffer.

By specification, a single recvmsg() invocation on a kTLS socket must deliver either:

  1. One or more contiguous DATA records (application payload).
  2. Exactly one non-DATA control record (e.g., TLS alerts, handshake renegotiation records, or heartbeat messages).

Under no circumstance should control records and data records be co-mingled or processed out of order in a single receive pass.

When a peer sends a TLS record containing zero plaintext bytes (e.g., an empty application data frame or zero-length alert), the decryption routines process the record and push the corresponding sk_buff to rx_list:

/* Simplified representation of vulnerable logic in net/tls/tls_sw.c */
static int tls_sw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
int flags, int *addr_len)
{
struct tls_context *tls_ctx = tls_get_ctx(sk);
struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx);
struct sk_buff *skb;
...
while (len && (skb = tls_wait_data(sk, flags, timeo, &err))) {
/*
* FLAW: When skb->len is 0, the record validation does not properly
* break or consume the control record type. Instead, the loop treats
* the record as empty, unlinks it, but fails to reset the record-type
* state tracker.
*/
if (skb->len == 0) {
tls_rx_rec_done(ctx);
kfree_skb(skb);
continue; /* Loop continues with stale record-type assumptions */
}
...
err = process_rx_list(ctx, skb, &len);
}
return copied;
}

Because the zero-length record check frees the skb via kfree_skb() without updating the parser state machine, a subsequent loop iteration encounters mismatched pointers in ctx->rx_list. When the next message arrives, the kernel references memory that was already returned to the kmalloc-512 or skbuff_head_cache slab allocator.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ kTLS USE-AFTER-FREE TIMELINE β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ T0: Peer queues Zero-Length Record followed by Malicious Control Frame β”‚
β”‚ T1: tls_sw_recvmsg() dequeues zero-length skb and frees via kfree_skb β”‚
β”‚ T2: Internal state flags fail to reset; rx_list tail pointer lingers β”‚
β”‚ T3: Attacker grooms kmalloc slab with controlled pseudo-skb payload β”‚
β”‚ T4: tls_sw_recvmsg() re-dereferences lingering pointer -> KERNEL UAF β”‚
β”‚ T5: Hijacks sk->sk_data_ready / function pointer -> Ring 0 Root Shell β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

In the wild, threat actors have operationalized this flaw into a reliable local root exploit targeting cloud VMs and Kubernetes pods:

  1. Local Foothold: The attacker acquires local unprivileged shell access (via an SSH credential, container escape, or a web application RCE in Python/PHP).
  2. Socket Initialization: The exploit opens a local loopback TCP connection, sets TCP_ULP to "tls", and programs symmetric session keys via setsockopt(..., SOL_TLS, TLS_RX).
  3. Payload Injection: Over the socket, the exploit transmits an encrypted sequence: a zero-length TLS application data frame immediately followed by an out-of-order control record.
  4. Triggering the Free: The exploit calls recvmsg() with flags set to read only a fraction of the buffer, forcing tls_sw_recvmsg into the zero-length processing branch where the sk_buff is freed while remaining referenced.
  5. Slab Spraying & Reallocation: The attacker rapidly sprays the kmalloc-1024 or skbuff_head_cache slab cache using sendmsg() with crafted ancillary data (SCM_RIGHTS) to occupy the vacated memory chunk with controlled data.
  6. Privilege Escalation: When the kernel performs a subsequent cleanup or poll operation, it calls a function pointer from the attacker-controlled slab object. The payload executes in Ring 0, modifies the current process credentials (commit_creds(prepare_kernel_cred(NULL))), and escapes to a root shell.

Exploitation attempts, both successful and failed, leave distinct traces in the kernel ring buffer (dmesg / /var/log/messages):

  • General Protection Faults: Look for crashes originating in net/tls/ routines:
    BUG: unable to handle page fault for address: ffff888012345678
    #PF: supervisor read access in kernel mode
    #PF: error_code(0x0000) - not-present page
    Workqueue: events tls_sk_proto_close
    RIP: 0010:tls_sw_recvmsg+0x3ba/0x780 [tls]
    Call Trace:
    <TASK>
    inet_recvmsg+0x54/0x130
    sock_recvmsg+0x3f/0x70
    __sys_recvmsg+0x8a/0x100
    do_syscall_64+0x58/0x80
  • KASAN Reports: Systems running kernels with Kernel Address Sanitizer (KASAN) enabled log explicit use-after-free alerts identifying kfree_skb as the release locus.
  • Suspicious Socket Allocation: Look for unprivileged processes (e.g., www-data, nobody, low-privilege service accounts) invoking setsockopt with level SOL_TCP (6) and option TCP_ULP (31) specifying the string "tls".
  • Credential Escalation Events: Audit for sudden process UID/GID transitions (auditd SYSCALL event for setuid or child processes spawned by low-privilege daemons with uid=0).

title: Linux Kernel kTLS Subsystem Crash or Panic
id: d82e1456-913a-4e2b-8711-2b8c9e253968
status: experimental
description: Detects kernel oops, GPFs, or KASAN use-after-free warnings originating in the kTLS subsystem, indicative of CVE-2025-39682 exploitation.
logsource:
product: linux
service: kernel
detection:
selection:
- 'tls_sw_recvmsg'
- 'BUG: unable to handle page fault'
- 'kernel NULL pointer dereference'
- 'KASAN: use-after-free in tls_sw_recvmsg'
condition: selection
level: critical
tags:
- attack.privilege_escalation
- attack.t1068
- cve.2025-39682

  1. Kernel Update: Upgrade to the latest distribution kernel maintenance release immediately:
    • RHEL 9 / Rocky / AlmaLinux: Apply RHSA-2026-ktls errata.
    • Ubuntu 24.04 / 22.04 LTS: Update to kernel 6.8.0-45-generic / 5.15.0-118-generic.
    • Debian 12 Bookworm: Apply linux-image-6.1.0-25-amd64 or later.
  2. CISA KEV Compliance: For US federal agencies and organizations governed by BOD 22-01, remediation must be completed and documented by October 9, 2026.

If an immediate kernel reboot cannot be scheduled, prevent unprivileged users from loading or binding to the kTLS subsystem by blacklisting the kernel module:

Terminal window
# Blacklist the kTLS kernel module
echo "install tls /bin/true" | sudo tee /etc/modprobe.d/disable-tls.conf
echo "blacklist tls" | sudo tee -a /etc/modprobe.d/disable-tls.conf
# If currently loaded and not actively required by critical web servers:
sudo modprobe -r tls

Note: Disabling kTLS falls back to standard user-space TLS processing (e.g., OpenSSL / BoringSSL), causing a minor CPU overhead increase without disrupting application connectivity.