Skip to content

Fix unbounded request decompression on IIS out-of-process (MaxRequestBodySize) - #69187

Merged
wtgodbe merged 2 commits into
mainfrom
wtgodbe/Port63343
Sep 11, 2026
Merged

wtgodbe merged 2 commits into
mainfrom
wtgodbe/Port63343

Conversation

@wtgodbe

@wtgodbe wtgodbe commented Sep 9, 2026

Copy link
Copy Markdown
Member

On IIS out-of-process hosting, IISMiddleware cleared the request body size limit (MaxRequestBodySize = null). RequestDecompressionMiddleware consumed that as an unbounded decompressed-body budget, allowing an anonymous decompression-bomb DoS (temporary, with amplification).

Gate the null-assignment behind the Microsoft.AspNetCore.Server.IISIntegration.ClearMaxRequestBodySize AppContext switch (default off). By default the server request body size limit is preserved; apps needing the legacy defer-to-IIS behavior can opt in.

Prevents unbounded request-body decompression on IIS out-of-process. Opt-out switch provided for compatibility.

… IIS out-of-process (MaxRequestBodySize)

## Description
On IIS out-of-process hosting, IISMiddleware cleared the request body size limit (MaxRequestBodySize = null). RequestDecompressionMiddleware consumed that as an unbounded decompressed-body budget, allowing an anonymous decompression-bomb DoS (temporary, with amplification).
## Fix
Gate the null-assignment behind the Microsoft.AspNetCore.Server.IISIntegration.ClearMaxRequestBodySize AppContext switch (default off). By default the server request body size limit is preserved; apps needing the legacy defer-to-IIS behavior can opt in.
## Customer Impact
Prevents unbounded request-body decompression on IIS out-of-process. Opt-out switch provided for compatibility.
## Regression
No. Long-standing behavior since 2.0; exposed via RequestDecompression (7.0+).
## Risk
Low. Minimal, gated change with opt-out. Product change validated identically on main; unit tests added. Local full build blocked by internal feed provisioning; relying on PR CI.
## Testing
Unit tests: default preserves limit, switch clears it, read-only untouched, absent feature. Verified end-to-end on main via real IIS Express out-of-process deploy.

----
#### AI description  (iteration 1)
#### PR Classification
Bug fix to address unbounded request decompression vulnerability in IIS out-of-process by changing the default behavior of MaxRequestBodySize handling.

#### PR Summary
This PR fixes a security issue where MaxRequestBodySize was being cleared by default in IIS out-of-process mode, allowing unbounded request decompression. The fix changes the default behavior to preserve the server's configured MaxRequestBodySize limit while providing an opt-in switch to restore the legacy behavior.

- `IISMiddleware.cs`: Changed default behavior to no longer clear MaxRequestBodySize; added `ClearMaxRequestBodySizeSwitch` AppContext switch to enable legacy behavior of clearing the limit
- `IISMiddlewareTests.cs`: Added comprehensive test coverage for MaxRequestBodySize handling including default behavior, opt-in switch behavior, read-only feature handling, and missing feature scenarios
<!-- GitOpsUserAgent=GitOps.Apps.Server.pullrequestcopilot -->
@wtgodbe
wtgodbe requested review from rokonec and a lite review from Copilot September 9, 2026 23:27
@github-actions github-actions Bot added the area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions label Sep 9, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new switch-controlled behavior isn’t fully covered by tests (the opt-in path and the “feature absent” case under the opt-in switch need explicit coverage and isolation).

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR addresses a security/compatibility issue in IIS out-of-process hosting where IISMiddleware previously cleared IHttpMaxRequestBodySizeFeature.MaxRequestBodySize, which could be interpreted by request decompression as an unbounded decompressed-body budget. The change preserves the server-side limit by default and introduces an AppContext switch to opt into the legacy “clear the limit” behavior.

Changes:

  • Gate clearing MaxRequestBodySize behind the Microsoft.AspNetCore.Server.IISIntegration.ClearMaxRequestBodySize AppContext switch (default: off).
  • Add unit tests to validate the default behavior (do not clear) and basic behavior when the feature is absent.
File summaries
File Description
src/Servers/IIS/IISIntegration/src/IISMiddleware.cs Adds an AppContext switch-controlled opt-in path for clearing MaxRequestBodySize, preserving the configured limit by default.
src/Servers/IIS/IISIntegration/test/Tests/IISMiddlewareTests.cs Adds tests around MaxRequestBodySize behavior and introduces test helpers for constructing an IISMiddleware instance and HttpContext.
Review details

Suppressed comments (1)

src/Servers/IIS/IISIntegration/test/Tests/IISMiddlewareTests.cs:560

  • DoesNotThrowWhenMaxRequestBodySizeFeatureAbsent currently runs with the AppContext switch default (off), so it doesn't exercise the new guarded code path. Setting the switch to true for this test (and resetting it in a finally) ensures we cover the opt-in path where the feature lookup happens, while still validating it doesn't throw when the feature is missing.
    [Fact]
    public async Task DoesNotThrowWhenMaxRequestBodySizeFeatureAbsent()
    {
        var nextInvoked = false;
        var context = new DefaultHttpContext();
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

- in-process must clear the limit on upgrade because its read loop enforces it
- out-of-process runs on Kestrel, which never enforces it once upgraded
- unblocks the three WebSocketsOutOfProcessTests failures

🧪 - Generated by Copilot
@rokonec

rokonec commented Sep 11, 2026 •

Copy link
Copy Markdown
Member

The three WebSocketsOutOfProcessTests failures in the last CI run are a real regression from this change, not infrastructure flakiness. Fixed in befb2e9.

What failed

IIS.FunctionalTests and IISExpress.FunctionalTests, the same three tests in each:

  • WebSocketsOutOfProcessTests.CanSendAndReceieveData
  • WebSocketsOutOfProcessTests.OnStartedCalledForWebSocket
  • WebSocketsOutOfProcessTests.WebReadBeforeUpgrade

The fix

Scope the assertion to in-process hosting, where it is meaningful:

if (context.Features.Get<IServerVariablesFeature>() is not null)
{
    Assert.Null(context.Features.Get<IHttpMaxRequestBodySizeFeature>().MaxRequestBodySize);
}

IISHttpContext implements IServerVariablesFeature; Kestrel does not. In-process coverage is unchanged, and no product code is touched.

@wtgodbe
wtgodbe merged commit 18c86e9 into main Sep 11, 2026
29 checks passed
@wtgodbe
wtgodbe deleted the wtgodbe/Port63343 branch September 11, 2026 16:28
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 12.0-preview1 milestone Sep 12, 2026
@BrennanConroy

Copy link
Copy Markdown
Member

/backport to release/10.0

@BrennanConroy

Copy link
Copy Markdown
Member

/backport to release/9.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/10.0 (link to workflow run)

@BrennanConroy

Copy link
Copy Markdown
Member

/backport to release/8.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/9.0 (link to workflow run)

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/8.0 (link to workflow run)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants