Nov 11, 2026·10 min read·2 visits
A numeric truncation error in Microsoft.DiaSymReader.Native when parsing Portable PDB Document tables leads to an undersized heap buffer allocation and subsequent heap-based buffer overflow. Unauthenticated attackers can achieve arbitrary code execution by convincing a user or service to load a crafted PDB file or .NET assembly.
CVE-2026-114159 is a heap-based buffer overflow vulnerability (CWE-122) in Microsoft.DiaSymReader.Native affecting Microsoft Visual Studio and the .NET Runtime on Windows. An integer truncation error during the parsing of oversized document names in Portable PDB symbol files causes an undersized heap allocation, leading to an out-of-bounds memory write and remote code execution.
CVE-2026-114159 is a heap-based buffer overflow vulnerability classified under CWE-122 (with an underlying mechanism tied to CWE-190 and CWE-197) that affects Microsoft Visual Studio and the .NET Runtime on Windows operating systems. The flaw resides within the native unmanaged symbol reader library, Microsoft.DiaSymReader.Native, which is distributed as architecture-specific binaries such as Microsoft.DiaSymReader.Native.amd64.dll and Microsoft.DiaSymReader.Native.x86.dll.
This component exposes Component Object Model (COM) unmanaged symbol reading interfaces—specifically ISymUnmanagedReader, ISymUnmanagedBinder, and ISymUnmanagedDocument. Both the Visual Studio debugger (devenv.exe) and the .NET runtime host (dotnet.exe) rely on these interfaces to parse and consume Program Database (PDB) files, including the cross-platform Portable PDB format, during debugging, stack trace generation, and profiling operations.
Because symbol resolution frequently occurs automatically when opening a solution, inspecting an assembly, or pulling packages from symbol servers and NuGet feeds, the symbol parser represents a directly reachable attack surface for untrusted file inputs. When processing a malformed Portable PDB containing oversized document name records, the library miscalculates the required destination buffer size due to an integer truncation error.
Consequently, the library allocates an undersized buffer on the process heap and subsequently performs an unbounded memory copy using the original, un-truncated length value. This out-of-bounds write corrupts adjacent heap memory structures, enabling an unauthenticated attacker to execute arbitrary code within the security context of the user running Visual Studio or the .NET application.
The root cause of CVE-2026-114159 lies in how Microsoft.DiaSymReader.Native parses the Document table within the CLI metadata streams of a Portable PDB file. According to the Portable PDB specification, the Document metadata table stores references to source code file paths used to build an assembly. Rather than storing contiguous plain-text strings, document names are encoded in the #Blob metadata stream as structured UTF-8 byte sequences consisting of a separator character followed by a series of part references pointing to path segments.
When a consumer invokes methods on ISymUnmanagedDocument (or enumerates documents via ISymUnmanagedReader::GetDocuments), the native reader reconstructs the full document path in memory. To do this, the parser iterates over the segments referenced in the #Blob stream, converts the UTF-8 segments into wide-character (UTF-16) strings, and computes the total character count required to hold the reassembled file path.
During this buffer size calculation, the length accumulation logic suffers from a numeric truncation error (CWE-197) or integer wraparound (CWE-190). Specifically, when summing the segment lengths or casting a 32-bit length variable (size_t or ULONG) into a narrower 16-bit integer type (such as USHORT or WORD), any document name exceeding the 16-bit boundary (65,535 bytes/characters) wraps around modulo $2^{16}$.
For example, if an attacker crafts a Document blob whose reconstructed path length equals 0x10020 (65,568 characters), a truncation to 16 bits yields an allocation request for only 0x0020 (32 characters). The memory allocator (HeapAlloc or malloc) succeeds and returns a small heap chunk corresponding to the truncated size. Immediately following allocation, the string assembly routine copies the path segments into the destination buffer using the original, un-truncated 32-bit length or iterates until all blob segments are exhausted, writing tens of kilobytes past the end of the allocated heap chunk.
While Microsoft.DiaSymReader.Native is shipped as a compiled native binary, the vulnerability mechanics follow a well-defined pattern in unmanaged C++ COM implementations that bridge metadata streams to WCHAR buffers. When reconstructing segmented document names from the #Blob stream, the vulnerable logic separates the size accumulation phase from the segment copying phase using mismatched integer widths.
// Conceptual representation of the vulnerable document name reconstruction logic
HRESULT ReconstructDocumentName(const BYTE* pBlob, ULONG cbBlob, WCHAR** ppwzName) {
ULONG totalChars = 0;
// Phase 1: Calculate total character length across all segments in the blob
for (SegmentIterator it(pBlob, cbBlob); it.HasNext(); it.Next()) {
totalChars += it.GetCurrentSegmentCharLength() + 1; // +1 for separator
}
// VULNERABILITY: Truncation from 32-bit ULONG to 16-bit USHORT
// If totalChars is 0x10010, allocChars wraps to 0x0010
USHORT allocChars = static_cast<USHORT>(totalChars);
// Undersized allocation on the process heap
WCHAR* pBuffer = static_cast<WCHAR*>(HeapAlloc(GetProcessHeap(), 0, allocChars * sizeof(WCHAR)));
if (!pBuffer) {
return E_OUTOFMEMORY;
}
// Phase 2: Copy segments using the un-truncated iterator bounds
WCHAR* pCursor = pBuffer;
for (SegmentIterator it(pBlob, cbBlob); it.HasNext(); it.Next()) {
ULONG segLen = it.GetCurrentSegmentCharLength();
// Out-of-bounds heap write occurs here once pCursor exceeds allocChars
memcpy(pCursor, it.GetCurrentSegmentData(), segLen * sizeof(WCHAR));
pCursor += segLen;
*pCursor++ = L'\\';
}
*ppwzName = pBuffer;
return S_OK;
}To remediate this class of vulnerability in the native symbol reader, the fix enforces consistent 32-bit unsigned integer types (ULONG or size_t) across both the accumulation and allocation paths, alongside explicit overflow checks prior to multiplying by sizeof(WCHAR).
// Conceptual representation of the remediated allocation and bounds check
HRESULT ReconstructDocumentNamePatched(const BYTE* pBlob, ULONG cbBlob, WCHAR** ppwzName) {
size_t totalChars = 0;
for (SegmentIterator it(pBlob, cbBlob); it.HasNext(); it.Next()) {
size_t segLen = it.GetCurrentSegmentCharLength();
// Check for addition overflow during accumulation
if (totalChars + segLen + 1 < totalChars) {
return COR_E_BADIMAGEFORMAT;
}
totalChars += segLen + 1;
}
// Enforce a strict upper bound on maximum path length and byte size
size_t allocBytes = 0;
if (FAILED(SizeTMult(totalChars, sizeof(WCHAR), &allocBytes))) {
return COR_E_BADIMAGEFORMAT;
}
WCHAR* pBuffer = static_cast<WCHAR*>(HeapAlloc(GetProcessHeap(), 0, allocBytes));
if (!pBuffer) {
return E_OUTOFMEMORY;
}
// Track remaining capacity during copy to prevent out-of-bounds writes
size_t remainingChars = totalChars;
WCHAR* pCursor = pBuffer;
for (SegmentIterator it(pBlob, cbBlob); it.HasNext(); it.Next()) {
size_t segLen = it.GetCurrentSegmentCharLength();
if (segLen + 1 > remainingChars) {
HeapFree(GetProcessHeap(), 0, pBuffer);
return COR_E_BADIMAGEFORMAT;
}
memcpy(pCursor, it.GetCurrentSegmentData(), segLen * sizeof(WCHAR));
pCursor += segLen;
*pCursor++ = L'\\';
remainingChars -= (segLen + 1);
}
*ppwzName = pBuffer;
return S_OK;
}> [!NOTE]
> By validating both arithmetic addition during segment iteration and integer multiplication (totalChars * sizeof(WCHAR)) via safe math helpers, the patched implementation prevents both narrow-type truncation and 32-bit integer overflow on x86 architectures. Returning COR_E_BADIMAGEFORMAT ensures that malformed PDB files are rejected cleanly before heap memory is modified.
Exploiting CVE-2026-114159 requires an attacker to deliver a crafted Portable PDB file (or a .NET Portable Executable with an embedded Portable PDB in its IMAGE_DEBUG_DIRECTORY) to a target environment where Microsoft.DiaSymReader.Native will parse it. Because no authentication is required (PR:N) and the vulnerability is triggered via file inspection (UI:R), multiple practical delivery vectors exist in modern development workflows.
First, an attacker can construct a malicious PDB file by modifying the #Blob stream and the Document metadata table (Table ID 0x30). In the Portable PDB format, a Document row contains a Name column, which is a blob index. The blob begins with a UTF-8 separator byte, followed by compressed unsigned integers indexing into the #Blob stream for each path segment. By repeating references to a single 1,024-byte path segment blob 65 times, the attacker achieves an expanded path length exceeding 65,536 characters while keeping the physical .pdb file size minimal.
Second, the attacker delivers this artifact through one of several common channels:
.snupkg symbol archive, or hosting a rogue symbol server endpoint that responds to automatic symbol resolution requests during debugging..dmp and .pdb pair to an engineer or automated crash-triage service running on Windows.When ISymUnmanagedBinder::GetReaderForFile (or stream-based equivalents) initializes the symbol reader and queries the document table, the undersized buffer is allocated on the Windows Low Fragmentation Heap (LFH) or standard process heap. Because Microsoft.DiaSymReader.Native heavily utilizes C++ COM objects (ISymUnmanagedDocument, ISymUnmanagedMethod), these objects are allocated on the same heap and begin with a pointer to their virtual method table (vtable).
By grooming the heap—allocating numerous legitimate Document records immediately before the oversized record—an attacker can position the undersized buffer directly before an active ISymUnmanagedDocument instance. When the overflow occurs, the attacker's UTF-16 payload overwrites the adjacent COM object's vtable pointer. When Visual Studio or the .NET runtime subsequently invokes a virtual method such as GetURL() or Release() on the corrupted COM interface, execution is redirected to an attacker-controlled address.
CVE-2026-114159 carries a CVSS v3.1 Base Score of 8.8 (High) with the vector CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H. The high severity rating reflects the fact that successful exploitation grants complete control over the target process with low attack complexity once user interaction occurs.
In a client-side scenario targeting Microsoft Visual Studio, code execution occurs within the security context of the software developer (devenv.exe or ServiceHub worker processes). Developer workstations typically possess high-value credentials, including SSH keys, cloud provider tokens (Azure, AWS), code-signing certificates, and write access to production source code repositories. Compromising a developer workstation via a malicious project or NuGet dependency enables immediate supply-chain pivot attacks.
In a server-side or CI/CD scenario targeting the .NET Runtime (dotnet.exe), the impact can be triggered without interactive human debugging. If an application or build agent loads untrusted assemblies and resolves stack trace source file names (for instance, via System.Diagnostics.StackTrace(Exception, bool fNeedFileInfo) when falling back to the native COM symbol reader on Windows), the overflow is triggered automatically upon exception handling.
Even when modern exploit mitigations such as Control Flow Guard (CFG) and Address Space Layout Randomization (ASLR) prevent arbitrary code execution, any un-handled out-of-bounds heap write corrupts heap metadata structures. This triggers an immediate STATUS_HEAP_CORRUPTION (0xC0000374) exception, terminating the host Visual Studio instance or .NET worker process and resulting in a complete denial of service (A:H).
Microsoft addressed CVE-2026-114159 in the November 2026 Patch Tuesday security updates by releasing updated builds of Visual Studio and servicing updates across all supported .NET versions on Windows. Organizations should prioritize applying these patches across both developer workstations and Windows build servers.
| Product Family | Affected Version Range | Patched Version |
|---|---|---|
| Microsoft Visual Studio 2026 | >= 18.11.0, < 18.11.4 | 18.11.4 |
| Microsoft Visual Studio 2026 | >= 18.12.0, < 18.12.0 (Serviced) | 18.12.0 (Serviced Release) |
| .NET 8.0 (Windows) | >= 8.0.0, < 8.0.34 | 8.0.34 |
| .NET 9.0 (Windows) | >= 9.0.0, < 9.0.23 | 9.0.23 |
| .NET 10.0 (Windows) | >= 10.0.0, < 10.0.15 | 10.0.15 |
| .NET 11.0 (Windows) | >= 11.0.0-preview.1, < 11.0.0 GA | 11.0.0 (GA) |
> [!IMPORTANT]
> Because Microsoft.DiaSymReader.Native can also be bundled directly inside standalone NuGet packages or self-contained .NET deployments, engineering teams must rebuild and redeploy self-contained Windows applications using the patched .NET SDKs to ensure the vulnerable native DLL is replaced.
For environments where immediate patching is not feasible, security teams should implement the following defensive workarounds:
devenv.exe, dotnet.exe, and vstest.console.exe.CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Visual Studio 2026 Microsoft | >= 18.11.0, < 18.11.4 | 18.11.4 |
Visual Studio 2026 Microsoft | >= 18.12.0, < 18.12.0 (Serviced) | 18.12.0 (Serviced Release) |
.NET 8.0 (Windows) Microsoft | >= 8.0.0, < 8.0.34 | 8.0.34 |
.NET 9.0 (Windows) Microsoft | >= 9.0.0, < 9.0.23 | 9.0.23 |
.NET 10.0 (Windows) Microsoft | >= 10.0.0, < 10.0.15 | 10.0.15 |
.NET 11.0 (Windows) Microsoft | >= 11.0.0-preview.1, < 11.0.0 | 11.0.0 (GA) |
| Attribute | Detail |
|---|---|
| Vulnerability Type | Heap-based Buffer Overflow (CWE-122) |
| Affected Component | Microsoft.DiaSymReader.Native |
| Attack Vector | Network / Crafted Portable PDB File (AV:N/UI:R) |
| CVSS v3.1 Score | 8.8 High |
| Security Impact | Arbitrary Code Execution (RCE) |
| Exploit Maturity | Unproven (No public PoCs observed) |
| CISA KEV Status | Not Listed |
A heap-based buffer overflow condition is a buffer overflow, where the buffer that can be overwritten is allocated in the heap portion of memory, generally meaning that the buffer was allocated using a routine such as malloc().
CVE-2026-114158 is a high-severity remote code execution vulnerability affecting Microsoft Visual Studio 2026 and multiple supported servicing branches of Microsoft .NET (.NET 8.0, 9.0, 10.0, and 11.0) on Windows. The flaw resides in the native symbol reader library, Microsoft.DiaSymReader.Native, and is triggered when parsing Portable Program Database (PDB) metadata containing malformed EmbeddedSource custom debug information records. By supplying a parent Record Identifier (RID) of zero or an out-of-bounds value, an attacker causes an integer underflow during 1-based to 0-based index conversion, leading to a heap-based buffer overflow and arbitrary code execution within the context of the host developer tool or runtime.
CVE-2026-114151 is a high-severity remote code execution vulnerability affecting Microsoft Visual Studio 2026 and multiple supported versions of the Microsoft .NET runtime on Windows. The flaw resides in the native Debug Information Access (DIA) symbol reader component, Microsoft.DiaSymReader.Native. When parsing Program Database (.pdb) files, the component fails to validate the length of serialized numeric records (specifically LF_DECIMAL structures) before unpacking them into a fixed-size stack buffer. An attacker who convinces a user or automated diagnostic process to load a crafted .pdb file can trigger a stack-based buffer overflow, resulting in arbitrary code execution within the context of the host process.
CVE-2026-105544 is a high-severity local elevation of privilege vulnerability in Microsoft .NET and Microsoft.TestPlatform.CLI. Improper access control on local inter-process communication mechanisms and execution brokers allows an authorized local attacker to cross security boundaries and execute arbitrary code in the context of a higher-privileged user running a test execution cycle.
CVE-2026-114152 is a high-severity remote code execution vulnerability affecting Microsoft Visual Studio 2026 and multiple servicing branches of the Microsoft .NET runtime (.NET 8.0, 9.0, 10.0, and 11.0) on Windows platforms. The vulnerability exists within the native symbol reader library, Microsoft.DiaSymReader.Native, specifically inside the DiaObjectFile::ApplyFixup method during the processing of Common Object File Format (COFF) relocation records. By supplying a malformed object file or Program Database (PDB) symbol file containing out-of-bounds relocation offsets or invalid symbol table indices, an unauthenticated attacker can trigger an untrusted pointer dereference (CWE-822) and a stack-based buffer overflow (CWE-121). Successful exploitation occurs when a victim opens, compiles, or debugs a malicious project or symbol artifact, leading to arbitrary code execution within the security context of the active developer environment or build process.
CVE-2026-118745 is a high-severity remote code execution vulnerability affecting Microsoft Visual Studio 2026 and multiple supported versions of the .NET runtime (8.0, 9.0, 10.0, and 11.0) on Windows systems. The flaw is a heap-based buffer overflow (CWE-122) located within the native symbol reading library, Microsoft.DiaSymReader.Native, specifically in the routines responsible for extracting and parsing Program Database (.pdb) line number metadata. An attacker can exploit this vulnerability by supplying a crafted .pdb file alongside a repository, project, or compiled binary. When a developer or automated diagnostic process parses the malformed debug symbols, an out-of-bounds heap write occurs, permitting arbitrary code execution within the security context of the active user process.
CVE-2026-109481 is a high-severity Cross-Site Request Forgery (CSRF) vulnerability in the ASP.NET Core Blazor Server and interactive component architecture. The flaw exists within the internal circuit state synchronization endpoint (`/_blazor/refresh`), which fails to enforce antiforgery token validation or verify cross-origin request headers. By inducing an authenticated victim to issue a cross-site request targeting a pre-allocated circuit identifier, an unauthenticated attacker can bind the victim's security principal to the attacker's active SignalR circuit, resulting in full privilege elevation within the application scope.