Automated Threat Modeling

Overview of CVE-2026-118750: Unauthenticated Memory Exhaustion in ASP.NET Core WebUtilities FileBufferingReadStream

A brief summary of CVE-2026-118750, an unauthenticated memory exhaustion issue in ASP.NET Core's FileBufferingReadStream. It covers the root cause, the lazy buffer rental fix in Microsoft.AspNetCore.WebUtilities 2.3.14, and the affected version ranges.

CVE Analysis

8 min read

Gaurav Sarraf
Gaurav Sarraf

2026-11-10

Overview of CVE-2026-118750: Unauthenticated Memory Exhaustion in ASP.NET Core WebUtilities FileBufferingReadStream
Experimental AI-Generated Content

This CVE analysis is an experimental publication that is completely AI-generated. The content may contain errors or inaccuracies and is subject to change as more information becomes available. We are continuously refining our process.

If you have feedback, questions, or notice any errors, please reach out to us.

[email protected]

Introduction

A buffer allocation flaw in ASP.NET Core's request body handling allowed unauthenticated clients to make a server reserve far more memory than the data they actually sent. For applications that accept multipart form uploads and still resolve an older Microsoft.AspNetCore.WebUtilities package, a stream of small requests was enough to push the process toward memory exhaustion and a denial of service.

Microsoft rates CVE-2026-118750 at CVSS 3.1 base 7.5 (High), with a temporal score of 6.5 and a maximum vendor severity of Important. The vector is CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H: network reachable, low complexity, no privileges, no user interaction, and impact limited to availability. The published assessment shows no confidentiality or integrity impact, so this is not a code execution or data theft issue.

At release, Microsoft's assessment listed "Exploited: No", "Exploitation Less Likely", and exploit code maturity "Unproven". OffSeq, with data current as of November 11, 2026 at 00:23 UTC, reported no source describing exploitation, no CISA KEV listing, no exploit indexed in Metasploit or Exploit DB, no indexed Nuclei template, and no attack traffic recorded by its Mirage sensors. No threat actor has been attributed. Microsoft credits NavSec4 for the report, which is a researcher acknowledgment, not attribution of malicious activity. Absence from these indexes does not prove absence of attacks elsewhere.

The interesting part of this CVE, and the reason we think it is worth a short review, is that the fix lives in a standalone NuGet package. Updating the .NET runtime on a host does not remediate it, and a parent package at the "right" version can still pull in a vulnerable child.

Technical information

What FileBufferingReadStream does

FileBufferingReadStream is the class ASP.NET Core uses to make request bodies, such as multipart form sections, rewindable so they can be read more than once. Microsoft's API documentation describes it as buffering content as it is read. Small bodies stay in memory, and once a body passes memoryThreshold, the contents are spooled to a temporary file on disk.

Root cause: the buffer was rented before any data arrived

In the vulnerable versions, the constructor rented a full memoryThreshold-sized array from the ArrayPool the moment the stream was created, before a single byte of the body had been read. The relevant constructor code before the fix was:

_bytePool = bytePool; if (memoryThreshold < _maxRentedBufferSize) { _rentedBuffer = bytePool.Rent(memoryThreshold); _buffer = new MemoryStream(_rentedBuffer); _buffer.SetLength(0); }

As a result, the memory cost of each buffered stream was set by the configured threshold, not by how much data the client sent. The commit message for the fix describes the problem directly: the preallocated buffer "may be much bigger than incoming data." This is a textbook instance of CWE-770, Allocation of Resources Without Limits or Throttling, which MITRE defines as allocating reusable resources for an actor without restrictions on their size or number, allowing an attacker to consume resources and deny them to other processes. Microsoft's advisory names memory as the exhausted resource.

Attack flow

Based on Microsoft's advisory and the patch, the disclosed exploitation sequence looks like this:

  1. An unauthenticated attacker sends an HTTP request carrying multipart form content to an application that processes it through the affected buffering path.
  2. ASP.NET Core constructs a FileBufferingReadStream for the body or section, and the vulnerable constructor immediately rents a memoryThreshold-sized array from the pool.
  3. The request itself can be very small, so the attacker pays almost nothing per request while the server reserves a full threshold-sized buffer.
  4. The attacker repeats this with many small multipart requests, and the server's memory consumption grows with the request count rather than the data volume, eventually exhausting memory and denying service.

The advisory does not publish a request payload, required request size, concurrency requirement, or exhaustion threshold, so we cannot be more precise about the practical cost of an attack than the patch itself implies.

The fix: PooledMemoryStream rents lazily

The patch introduces an internal PooledMemoryStream class in src/Shared/PooledMemoryStream.cs and replaces the eager rental in the constructor:

_bytePool = bytePool; if (memoryThreshold < _maxRentedBufferSize) { _buffer = new PooledMemoryStream(bytePool, memoryThreshold); }

The PooledMemoryStream constructor only stores the pool and a maxCapacity (the old memoryThreshold). It rents nothing. All allocation happens in EnsureCapacity, which runs only when a write needs more room:

private void EnsureCapacity(int requiredCapacity) { if (requiredCapacity > _maxCapacity) { throw new IOException("Memory threshold exceeded."); } if (_buffer != null && requiredCapacity <= _buffer.Length) { return; } if (requiredCapacity == 0) { return; } var newCapacity = _buffer == null ? requiredCapacity : Math.Max(requiredCapacity, Math.Min(_buffer.Length * 2, _maxCapacity)); var newBuffer = _bytePool.Rent(newCapacity); ...

This gives three properties:

  • No data, no allocation. An empty body, or a connection that never sends a byte, never touches the pool.
  • Memory grows with the input. The first rent equals the size of the first write. After that, capacity roughly doubles, and the previous array is returned to the pool once its contents are copied.
  • The ceiling stays in place. Capacity never exceeds maxCapacity, and requesting more throws IOException("Memory threshold exceeded."). Write computes checked(_position + count), so an integer overflow cannot be used to bypass the limit.

Disk spooling and cleanup changes

The patch also reworks the Read and ReadAsync paths that move buffered data to a temporary file. The _rentedBuffer field is gone. When the in-memory buffer is a PooledMemoryStream, its logical contents (pooledBuffer.Buffer, up to Length) are written directly to the temporary file, and the old stream is wrapped in using (oldBuffer) so its pooled array is always returned. The fallback path for buffers that are not pooled now returns its temporary rented array in a try/finally. Before the fix, an exception during that copy would leak the array. Because PooledMemoryStream.Dispose() now owns the pooled memory, the _bytePool.Return(_rentedBuffer) call was removed from FileBufferingReadStream.Dispose.

Patch information

Microsoft fixed CVE-2026-118750 in Microsoft.AspNetCore.WebUtilities 2.3.14, released November 10, 2026. The source change is commit 9a26c7414a4fbff45535c0830253c1b4479b0073 in dotnet/aspnetcore, titled "[release 2.3] Make FileBufferingReadStream lazily rent buffer". The commit message notes that it backports an internal fix from Microsoft's Azure DevOps repository to the 2.3 branch.

The commit adds 774 lines and removes 41, mostly tests. A new FileBufferingReadStreamTests case uses a mocked pool to read a 10-byte body with a 16-byte threshold. Nothing is rented at construction, then rents occur in order at 4, 8, and 16 bytes, with each earlier buffer returned and all three returned after disposal. A second test uses a strict mock pool to confirm that empty content never calls Rent. The new PooledMemoryStreamTests.cs (404 lines) covers growth, seeking, zero-filled sparse writes, maximum capacity enforcement, overflow, and returning each buffer exactly once on dispose.

Applying the fix requires attention to how the package is resolved:

  1. Resolve WebUtilities to 2.3.14 or later. The fix lives inside the standalone package, so updating the .NET runtime on the machine does not fix it. Microsoft states explicitly that a runtime update does not change an application's standalone package references.
  2. Check transitive resolution. Run the following to see which version an application actually resolves:
dotnet list package --include-transitive
  1. Watch the Microsoft.AspNetCore.Http trap. The NuGet metadata for Microsoft.AspNetCore.Http 2.3.14 declares Microsoft.AspNetCore.WebUtilities >= 2.3.13, while the advisory requires WebUtilities 2.3.14 or later. A parent package at 2.3.14 therefore does not, on its own, guarantee a patched child. Where an older version arrives transitively, Microsoft's advisory says to add a direct WebUtilities reference to override it.
  2. Rebuild and redeploy. Microsoft lists rebuilding and redeploying as part of the fix, since the corrected dependency only takes effect once it ships with the application.

Microsoft does not publish a configuration workaround such as a specific memory limit, request size cap, rate limit, or WAF rule. MITRE's general CWE-770 guidance (per-user resource limits and architectural throttling) is sound design advice, but it is not a validated mitigation for this specific CVE.

Affected systems and versions

  • Package: Microsoft.AspNetCore.WebUtilities
  • Affected per Microsoft's GitHub advisory: versions 2.3.0 through 2.3.13, inclusive
  • Affected per the CVE and NVD records: versions from 2.3.12, up to but excluding 2.3.14
  • Fixed: version 2.3.14
  • Platforms: Microsoft lists any supported operating system and all architectures
  • Transitive exposure: applications referencing Microsoft.AspNetCore.Http, including version 2.3.14, if WebUtilities resolves below 2.3.14

The records disagree only on the lower boundary, not on the patched version. Because Microsoft's package advisory is broader, we recommend treating anything from 2.3.0 through 2.3.13 as in scope, particularly for dependency trees that pin versions older than 2.3.12. Exposure depends on the package version each application resolves, not on the operating system or the installed runtime.

Vendor security history

The CVE input lists the vendor as unknown, but the official CVE record identifies Microsoft Corporation as the vendor and Microsoft as the assigning CNA. ASP.NET Core is Microsoft's open-source, cross-platform framework for building modern .NET web applications. For rough context, W3Techs reports ASP.NET broadly at 4.2% of websites whose server-side language it can identify (November 5, 2026). That figure covers ASP.NET as a whole and says nothing about how many deployments run vulnerable WebUtilities versions.

On Microsoft's broader track record, the Cyber Safety Review Board's review of the summer 2023 Exchange Online intrusion found the incident preventable and concluded that Microsoft's security culture was inadequate and required an overhaul. DHS's April 2, 2024 release of the findings described decisions that deprioritized enterprise security investment and rigorous risk management, and recommended that Microsoft publish a reform plan with specific timelines. Microsoft's July 2026 Secure Future Initiative progress material describes efforts to embed security across culture, governance, and engineering. None of this history relates to exploitation of CVE-2026-118750. For this issue, the concrete vendor response is the November 10, 2026 advisory and the WebUtilities 2.3.14 fix.

References

Detect & fix
what others miss

Works with
  • GitHub
  • GitLab
  • Bitbucket
  • Azure DevOps Services
  • Gerrit
  • CVS
  • Jira
  • Linear
  • Slack
  • Security Compass
Explore integrations
Security magnifying glass visualization