CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-20931
8.02.22%

Dial 'E' for Exploit: Dropping Calls and Privileges with CVE-2026-20931

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 16, 2026·6 min read·20 visits

Weaponized

Executive Summary (TL;DR)

The Windows Telephony Service trusts user input blindly when setting up async notification channels. Instead of a mailslot, attackers can pass a file path. The service then writes 4 bytes of attacker-controlled data to that file as 'NETWORK SERVICE'. This is a text-book write-what-where primitive leading to EoP.

A logic flaw in the Windows Telephony Service (TapiSrv) allows for an arbitrary file write primitive via the ClientAttach RPC method. By failing to validate the 'pszDomainUser' parameter, the service allows an attacker to direct asynchronous event notifications—specifically a 4-byte attacker-controlled DWORD—to any file writable by the NETWORK SERVICE account. This can be leveraged for Local Privilege Escalation (LPE) to SYSTEM or Remote Code Execution (RCE) in specific server configurations.

The Hook: Who Still Uses Fax Machines?

In the year of our Lord 2026, you might be asking yourself: "Why does Windows still have a Telephony Service?" The answer is the same reason win32k.sys is still a mess of spaghetti code—backward compatibility is a hell of a drug. The Telephony Application Programming Interface (TAPI) is the subsystem responsible for managing modems, faxes, and voice calls. While you're busy using Teams or Zoom, tapisrv.dll is quietly humming along in the background, running as NETWORK SERVICE inside an svchost.exe container, waiting for the 90s to call.

But here's the kicker: TapiSrv isn't just a dusty relic; it exposes a rich RPC interface (tapsrv) over a named pipe. Security researchers love RPC interfaces because they are often the soft underbelly of Windows services. They parse complex structures, handle state, and, in this case, manage asynchronous callbacks. And as we all know, handling callbacks in Windows is like juggling chainsaws—eventually, someone drops one, and it usually lands on the stack.

Enter CVE-2026-20931. This isn't a complex heap feng-shui exploit involving 17 different allocation grooming primitives. No, this is much stupider. This is the code equivalent of a bank teller asking a robber, "Where would you like me to deposit this money?" and actually listening when the robber says, "In my bag."

The Flaw: Trusting the Caller ID

To understand the vulnerability, we have to look at how TapiSrv handles asynchronous events. When a client (like a TAPI application) wants to know about incoming calls or line changes, it needs a way for the server to call it back. Typically, RPC interfaces use context handles or dedicated callback interfaces for this. TapiSrv, being an architectural antique, uses Mailslots.

When a client connects via the ClientAttach RPC method, it provides a string parameter called pszDomainUser. Ostensibly, this string is supposed to be the name of a mailslot (e.g., \\.\mailslot\MyTAPIClient) where the server should send notifications. The server takes this string and passes it directly to CreateFileW with GENERIC_WRITE permissions.

Here lies the logic bomb: There is no validation. The code never checks if the string actually starts with \\.\mailslot\. It just takes whatever path you give it and tries to open it. If you pass C:\Windows\Temp\oops.txt, the service dutifully opens a handle to that file. If you pass a UNC path to a remote SMB share, it tries to authenticate to it. It is a blind file-open primitive running with NETWORK SERVICE privileges.

The Code: The Smoking Gun

Let's look at the disassembly provided by the researchers at PT Swarm. The vulnerability is painfully obvious once you know where to look. In tapisrv.dll, the handler for ClientAttach does roughly this:

// The "Before" Code (Vulnerable)
if (wcslen(pszDomainUser) > 0)
{
    // Direct pass-through of user input to CreateFileW
    if ((ptClient->hMailslot = CreateFileW(
                pszDomainUser,          // <--- TAINTED INPUT
                GENERIC_WRITE,
                FILE_SHARE_READ,
                NULL,
                OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL,
                NULL
            )) != INVALID_HANDLE_VALUE)
    {
        // Proceed to store the handle
        goto ClientAttach_AddClientToList;
    }
}

The pszDomainUser variable is fully controlled by the attacker via the RPC packet. There is no wcsstr looking for "mailslot", no Access Control List (ACL) check, nothing. It just assumes the caller is a gentleman playing by the rules.

The patch acts as a sanity check. Microsoft likely added a wcsncmp or IsMailslot verification step to ensure the path targets the Mailslot device namespace before calling CreateFileW. This kills the arbitrary file write because you can't simply create a file named C:\Windows\System32\... inside the \Device\Mailslot namespace.

The Exploit: Dialing for SYSTEM

So we can open a file. That's cool, but we need to write to it to cause damage. TapiSrv is helpful here. Once the handle is open, the service uses it to send event notifications. Specifically, when a TAPI event occurs, the service writes a specific data structure to this handle.

The attack chain, as detailed by PT Swarm, works like this:

  1. Connect: Call ClientAttach via RPC. Set pszDomainUser to the path of the file you want to corrupt (e.g., a service DLL or a config file writable by NETWORK SERVICE).
  2. Prime the Payload: Call the Initialize method. This allows you to set an InitContext, which is a 4-byte DWORD. This is our payload. We control these 4 bytes.
  3. Register: Call LRegisterRequestRecipient to tell the service, "Hey, send me updates about phone calls."
  4. Trigger: Call TRequestMakeCall to simulate a telephony event.

When the event triggers, TapiSrv takes our handle (the file we targeted) and writes our InitContext (the 4 bytes we chose) into it.

While a 4-byte write sounds limited, it is often enough to corrupt a binary header, flip a configuration flag, or modify a pointer if the target file structure is known. If the attacker can find a DLL that NETWORK SERVICE can write to (often found in poorly secured third-party software directories), they can overwrite the entry point or code section, leading to code execution when that DLL is loaded.

The Impact: Why Should We Panic?

The primary impact here is Local Privilege Escalation (LPE). An attacker starting with low privileges can elevate to SYSTEM. The NETWORK SERVICE account is not SYSTEM, but it has significant privileges, including network access and write permissions to various temporary and system directories. By hijacking a file used by a higher-privileged process, the attacker bridges the gap.

However, the nightmare scenario is Remote Code Execution (RCE). TAPI has a "Server" mode. If a machine is configured as a TAPI Server, it exposes this RPC interface to the network. An attacker on an adjacent network could perform this same exploit remotely. They could target a file on a network share or a local file on the server, writing their malicious 4-byte payload to gain a foothold. Given the CVSS score of 8.0 and the "Adjacent" vector, this is a very real threat for enterprise environments running legacy telephony infrastructure.

The Fix: Hanging Up

Microsoft patched this in the January 2026 update cycle. The fix involves strictly validating that the pszDomainUser parameter is a valid mailslot path. If you are a developer, the lesson here is simple: Never pass user input directly to filesystem APIs. Always whitelist expected patterns (e.g., ensure the string starts with \\.\mailslot\).

For administrators, apply the patch immediately. If you cannot patch, you should verify if TAPI Server sharing is enabled and disable it via the registry (HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Telephony\Server\DisableSharing = 1). This kills the remote attack vector, though the local vector remains until the binary is updated.

Ultimately, this vulnerability is a reminder that Windows is a geological dig site of code layers. Just because a feature was written in 1996 doesn't mean it isn't running on your 2026 Server Core instance, waiting to be exploited.

Official Patches

MicrosoftMicrosoft Security Update Guide for CVE-2026-20931

Technical Appendix

CVSS Score
8.0/ 10
CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
EPSS Probability
2.22%
Top 16% most exploited

Affected Systems

Windows 10 (1607 - 22H2)Windows 11 (22H2 - 24H2)Windows Server 2016Windows Server 2019Windows Server 2022Windows Server 2025

Affected Versions Detail

Product
Affected Versions
Fixed Version
Windows 10
Microsoft
< 10.0.19045.680910.0.19045.6809
Windows 11
Microsoft
< 10.0.22631.649110.0.22631.6491
AttributeDetail
CWE IDCWE-73 (External Control of File Name or Path)
Attack VectorAdjacent Network (AV:A)
Privileges RequiredLow (PR:L)
CVSS v3.18.0 (High)
EPSS Score2.22%
Exploit StatusWeaponized (Detailed Technical Report Available)

MITRE ATT&CK Mapping

T1068Exploitation for Privilege Escalation
Privilege Escalation
T1543Create or Modify System Process
Persistence
CWE-73
External Control of File Name or Path

The software allows user input to control or influence paths or file names that are used in filesystem operations.

Known Exploits & Detection

PT SwarmComprehensive technical write-up detailing the discovery and exploitation primitives.

Vulnerability Timeline

Bounty Awarded ($5,000)
2025-12-23
CVE-2026-20931 Assigned
2025-12-29
Patch Released by Microsoft
2026-01-13
Full Exploit Details Published
2026-01-19

References & Sources

  • [1]Sergey Bliznyuk (Finder) Twitter

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.