Inside the Fix: AI-Powered Root Cause Analysis of CVE-2025-60719

Maor Dahan

Dec 08, 2025

Maor Dahan

Maor Dahan

Written by

Maor Dahan

Maor Dahan is a Senior Security Researcher at Akamai with more than a decade of experience in the cybersecurity industry. He specializes in operating system internals, vulnerability research, and malware analysis. Maor also has extensive experience designing and developing advanced detection and prevention mechanisms for innovative security products such as EDR, EPP, and virtualization-based security.

Share

Executive summary

Akamai researchers have created a new AI capability for instant root cause analysis. The tool is a supervised multi-agent system, dubbed PatchDiff-AI. In this blog post, we are using it for deep analysis of CVE-2025-60719, which affects almost all Windows versions. 

  • The vulnerability: A use-after-free (UAF) vulnerability in the Windows Ancillary Function Driver (afd.sys) for Winsock caused by a race condition

  • The impact: Local privilege escalation; an attacker with low privileges can manipulate the kernel memory and gain system privileges

  • Root cause: The driver failed to prevent a socket endpoint from being unbound (freed) while other operations (like Transfer, GetInformation, or Connect) were actively dereferencing its associated objects

  • The fix: Microsoft added a synchronization barrier mechanism (AfdPreventUnbind / AfdReallowUnbind) to explicitly lock the endpoint state during critical operations

Keep reading to learn how the PatchDiff-AI tool can be used to quickly analyze the root cause of a high-impact Patch Tuesday vulnerability and enable security teams to better detect and mitigate one-day vulnerabilities.

The vulnerability

CVE-2025-60719 represents a significant flaw in the Windows kernel networking stack, specifically within afd.sys, the cornerstone behind the Winsock API. A successful exploitation enables a low-privilege process to gain system privileges. However, we’ve tested our exploit within an AppContainer process, and it failed because of insufficient permissions. 

The vulnerability affects many Windows products, including all the following Windows versions:

  • Windows Server — 2008 SP2 (x86/x64), 2008 R2 SP1, 2012, 2012 R2, 2016, 2019, 2022, 2022 23H2, 2025

  • Windows 11 — 23H2, 24H2, 25H2 

  • Windows 10 — versions 1607, 1809, 21H2, 22H2 

  • Other discontinued versions

Such a wide spectrum of affected versions increases the attack surface significantly.

Root cause analysis

Using PatchDiff-AI, we can quickly analyze the security patch that, according to the vendor advisory, fixes the vulnerability. Reading the tool’s results indicates that the relevant code changes involve the methods AfdSocketTransfer*, AfdGetInformation, AfdBind, and AfdConnect.

A closer look reveals that the root cause of this vulnerability lies in the lifecycle management of the AFD Endpoint structure (named AFD_ENDPOINT) and the lack of atomicity (concurrent operations synchronization) between fetching an object pointer and using it.

Between the changes

The PatchDiff-AI tool highlighted one component directly related to the vulnerability’s core logic — the Ancillary Function Driver (afd.sys), which implements Windows’ core transport-layer networking support. It provides the Winsock interface, manages network sockets, and handles other I/O-related functionalities.

The tool analysis is based on the fixed version 10.0.26100.7171, as part of the KB5068861 security update, and tested against the vulnerable version 10.0.26100.6899, which is part of the KB5066835 security update.

There are five modified functions in total, and all of them were classified as security-related by the tool.

By analyzing the AfdGetInformation function, we can identify the code block that is now protected by blocking the unbind operation, preventing the socket from being released (Figure 1). Since we know this change refers to the socket lifecycle and interferes with its state, we can fairly assume this is related to a UAF vulnerability.

By analyzing the AfdGetInformation function, we can identify the code block that is now protected by blocking the unbind operation, preventing the socket from being released (Figure 1). Fig. 1: BinDiff view of the patched afd!AfdGetInformation alongside its previous version

Ancillary Function Driver — quick start

There are some comprehensive articles about how Ancillary Function Driver (afd.sys) works and how to use it. In short, this is a Windows component that is responsible for serving the Winsock API. It makes it possible for low-privilege processes to use the network stack for TCP/IP and other communication protocols.

In Figure 2, we find many reference binaries that call afd.sys through input/output controls (IOCTLs). And we can understand which call is related to which interface, connecting the dots between the user-mode application calls and the kernel module logic activation. It will help us later to perform direct calls to the driver and debug the driver's behavior.

In Figure 2, we find many reference binaries that call afd.sys through input/output controls (IOCTLs). Fig. 2: Winsock layered architecture diagram (Source: https://recon.cx/2015/slides/recon2015-20-steven-vittitoe-Reverse-Engineering-Windows-AFD-sys.pdf)

Into the logic

The vulnerability is a classic race condition that leads to a UAF scenario. It affects multiple dispatch routines, including AfdSocketTransfer*, AfdGetInformation, AfdBind, and AfdConnect.

The core issue arises when a user-mode application issues a specific IOCTL request while simultaneously closing the socket in a separate thread. In the unpatched version, the driver fetched pointers to the Endpoint, File Object, or Device Object and used them without ensuring that the underlying memory wasn't being freed by the concurrent close operation. This created a window in which the kernel operated on invalid memory, allowing a local attacker to corrupt kernel memory or gain elevated privileges.

When a process calls the afd!AfdGetInformation function for a specific information class using a handle of a bound socket (listen), it will involve checking some required conditions, such as the socket type and its protocol layer. Then, if we follow the call flow, we can find that the underlying function has a switch case for the different operations that the caller can use.

The vulnerable code block resides within the AFD_MAX_PATH_SEND_SIZE case (Figure 3). In other words, hitting the vulnerable path will require the caller to provide the correct values when calling the interface, and the socket to be in a connected state.

class AFD_INFORMATION_CLASS(IntEnum):
   AFD_INLINE_MODE = 1  # s: BOOLEAN
   AFD_NONBLOCKING_MODE = 2  # s: BOOLEAN
   AFD_MAX_SEND_SIZE = 3  # q: ULONG
   AFD_SENDS_PENDING = 4  # q: ULONG
   AFD_MAX_PATH_SEND_SIZE = 5  # q: ULONG
   AFD_RECEIVE_WINDOW_SIZE = 6  # q; s: ULONG
   AFD_SEND_WINDOW_SIZE = 7  # q; s: ULONG
   AFD_CONNECT_TIME = 8  # q: ULONG (seconds)
   AFD_CIRCULAR_QUEUEING = 9  # s: BOOLEAN
   AFD_GROUP_ID_AND_TYPE = 10  # q: AFD_GROUP_INFO
   AFD_REPORT_PORT_UNREACHABLE = 11  # s: BOOLEAN
   AFD_REPORT_NETWORK_UNREACHABLE = 12  # s: BOOLEAN
   AFD_DELIVERY_STATUS = 14  # q: SIO_DELIVERY_STATUS
   AFD_CANCEL_TL = 15  # s: void
Fig. 3: Enum of the possible classes AfdGetInformation function’s supported

In Figure 4, you can find a decompiled version of the vulnerable code (before) compared with the patched code (after).

In Figure 4, you can find a decompiled version of the vulnerable code (before) compared with the patched code (after). Fig. 4: Before and after applying the patch

The race condition

The afd.sys driver maintains the lifecycle of the endpoint, and the Endpoint object can be accessed concurrently from multiple threads. In Figure 5, the m_Endpoint->State represents the state of the socket. 

The afd.sys driver maintains the lifecycle of the endpoint, and the Endpoint object can be accessed concurrently from multiple threads. In Figure 5, the m_Endpoint->State represents the state of the socket. Fig. 5: Conditionally scope the execution to the bound and connected states (line 171)

To keep the socket in a valid state, the kernel module should handle it with extreme care. In this case, there is a window during which the state can be changed through another thread, and eventually free the endpoint altogether using the unbind control command.

A local attacker can exploit this by creating a "race" between two threads:

  • Thread A: Repeatedly sends a vulnerable IOCTL (e.g., IOCTL_AFD_GET_INFORMATION)

  • Thread B: Repeatedly binds and unbinds the socket handle

If Thread B wins the race after Thread A has fetched the pointer but before Thread A uses it, Thread A will dereference freed memory.

Crashing the party

Using the PatchDiff-AI report and the other resources, we can understand how to use the afd!AfdGetInformation function, and call it with the correct arguments to win the race (Figure 6).

Fig. 6: Proof of concept code that triggers the vulnerability

In Figure 7, you can find the call stack of the crash when it calls AfdGetInformation to the point where there is a PageFault exception.

In Figure 7, you can find the call stack of the crash when it calls AfdGetInformation to the point where there is a PageFault exception. Fig. 7: The faulting flow’s call stack

Attack vector 

This is a local privilege escalation bug that only affects the local system. An attacker who can execute arbitrary code from a low-privilege local process can exploit the race condition and gain higher privileges.

Although the PatchDiff-AI tool is not intended for creating an exploit, it can help with understanding the alleged exploit procedure.

  • Initialization: The attacker opens a valid AfdSocket using NtCreateFile().

  • Grooming/spraying: While not strictly necessary for the crash, reliable exploitation for EoP often involves heap spraying to replace the freed AFD_ENDPOINT with a fake structure controlled by the attacker.

  • Triggering: The attacker spawns two threads. Thread 1 loops on NtDeviceIoControlFile with the vulnerable IOCTL (e.g., IOCTL_AFD_GET_INFORMATION). Thread 2 loops on consecutive IOCTL_AFD_BIND and IOCTL_AFD_UNBIND.

  • Execution: When the race is won, the kernel executes a call (like IoGetRelatedDeviceObject) on the attacker's fake object, leading to kernel memory manipulation.

How to secure your system

  • Apply the patch: The only effective protection is to install the relevant Windows security update. The patch hardens afd.sys by strictly enforcing the unbind barrier.

  • Mitigation: Using a SIGMA or YARA rule set to identify the interaction with AFD that could indicate an exploitation attempt may reduce the threat. Tracing processes that initiate the IOCTL calls to the afd driver, and trying to spray the kernel pool memory using repeated calls, may be sufficient in most cases (Figure 8).

  • Detection: Since the AFD endpoint (socket) is ultimately exposed through the Windows I/O subsystem as a file handle, we can intercept the IRP calls and monitor for suspicious activities, especially of disconnected endpoints.

import "pe"

rule CVE_2025_60719 {
    meta:
        description = "Detects exploits for CVE-2025-60719 targeting afd.sys"
        author      = "Maor Dahan"
        date        = "2025-12-01"
        reference   = "https://github.com/akamai/CVE-2025-60719-AFD.SYS"

    strings:
        // Core Indicators - The specific device name is strong indicator
        $str_device  = "\\Device\\Afd\\Endpoint" ascii wide
	   $str_device_double  = "\\\\Device\\\\Afd\\\\Endpoint" ascii

        
        // Specific IOCTL constants used in the exploit
        // 0x12003 = IOCTL_AFD_BIND
        $ioctl_str_bind = "0x12003" ascii
        $ioctl_hex_bind = { 03 20 01 00 }
        
        // 0x12113 = IOCTL_AFD_UNBIND
        $ioctl_str_unbind = "0x12113" ascii
        $ioctl_hex_unbind = { 13 21 01 00 }
        
        // 0x1207B = IOCTL_AFD_GET_INFORMATION
        $ioctl_str_info = "0x1207B" ascii
        $ioctl_hex_info = { 7B 20 01 00 }

    condition:
        ($str_device or $str_device_double) and 
        (
            (
                pe.is_pe and
                pe.imports("ntdll.dll", "NtDeviceIoControlFile") and
                all of ($ioctl_hex_*)
            )
        or
            (
                not pe.is_pe and
                (
                    (
		       all of ($ioctl_str_*) or
		       3 of ($ioctl_*)
		   )
                )
            )
        )
}
Fig. 8: Sample YARA rule for identifying potential threats, both binaries and scripts

Final thoughts

By using PatchDiff-AI you can automate the correlation between binary changes and security logic, and rapidly pinpoint the root cause without getting lost in the noise of irrelevant code modifications. This allows security teams to act quickly to prevent one-day exploits. 

The CVE-2025-60719 case study highlights the complexity of patch management in kernel drivers and how the PatchDiff-AI tool’s analysis can provide insightful details for various purposes.

Maor Dahan

Dec 08, 2025

Maor Dahan

Maor Dahan

Written by

Maor Dahan

Maor Dahan is a Senior Security Researcher at Akamai with more than a decade of experience in the cybersecurity industry. He specializes in operating system internals, vulnerability research, and malware analysis. Maor also has extensive experience designing and developing advanced detection and prevention mechanisms for innovative security products such as EDR, EPP, and virtualization-based security.

Tags

Share

Related Blog Posts

Security Research
One Is a Fluke, 3 Is a Pattern: MCP Back-End Vulnerabilities
May 12, 2026
Akamai researchers uncover vulnerabilities in three MCP servers. Learn about CVE-2025-66335 and how to secure your AI-to-backend connection.
Security Research
XZ Utils Backdoor — Everything You Need to Know, and What You Can Do
CVE-2024-3094 is a backdoor in XZ Utils that can affect multitudes of Linux machines. We share the critical information about it, as well as mitigation steps.
Security Research
Honey, I Lost My Credentials! Finding Plaintext Credentials on the Internet
March 28, 2024
Sometimes the best findings are the accidental ones. See how Akamai Hunt found a customer’s plaintext credentials exposed on the internet.