Skip to content

Scope default CSRF middleware to endpoints opting in via IAntiforgeryMetadata#67460

Merged
DeagleGross merged 4 commits into
dotnet:mainfrom
DeagleGross:deaglegross-dmkorolev-csrf-skip-when-no-metadata
Jun 30, 2026
Merged

Scope default CSRF middleware to endpoints opting in via IAntiforgeryMetadata#67460
DeagleGross merged 4 commits into
dotnet:mainfrom
DeagleGross:deaglegross-dmkorolev-csrf-skip-when-no-metadata

Conversation

@DeagleGross

Copy link
Copy Markdown
Member

Aligns CsrfProtectionMiddleware with classic AntiforgeryMiddleware: validation runs only when the matched endpoint has IAntiforgeryMetadata { RequiresValidation: true }. Endpoints without metadata (plain MapPost, plain [HttpPost]) pass through, matching .NET 10 behavior — so no customer endpoint that worked on .NET 10 will start failing on .NET 11.

Blazor SSR and RDF form binding stay protected because they already attach RequireAntiforgeryTokenAttribute automatically. The MiddlewareInvokedKeys.CsrfProtection sentinel is still set unconditionally to preserve the FormFeature backstop contract from #67082.

Fixes #67424

DeagleGross and others added 2 commits June 29, 2026 14:41
CsrfProtectionMiddleware now mirrors the classic AntiforgeryMiddleware: it only runs DefaultCsrfProtection.ValidateAsync when the matched endpoint carries IAntiforgeryMetadata with RequiresValidation = true. Endpoints with no metadata, or with DisableAntiforgery() (RequiresValidation = false), pass through without recording an IAntiforgeryValidationFeature verdict.

The MiddlewareInvokedKeys.CsrfProtection sentinel continues to be set unconditionally so the FormFeature antiforgery backstop (dotnet#67082) still recognizes that an antiforgery-style middleware ran on the request.

Tests updated to attach RequireAntiforgeryTokenAttribute on endpoints whose intent is to exercise the validation path, and new tests added covering (a) no-metadata pass-through, (b) DisableAntiforgery pass-through, and (c) opted-in cross-site denial — all three asserting the sentinel is still set.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@DeagleGross
DeagleGross requested a review from javiercn June 29, 2026 12:55
@DeagleGross DeagleGross self-assigned this Jun 29, 2026
Copilot AI review requested due to automatic review settings June 29, 2026 12:55
@DeagleGross
DeagleGross requested a review from halter73 as a code owner June 29, 2026 12:55
@DeagleGross DeagleGross added bug This issue describes a behavior which is not expected - a bug. feature-antiforgery labels Jun 29, 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.

Pull request overview

Scopes the auto-injected CsrfProtectionMiddleware so it mirrors AntiforgeryMiddleware: it only performs CSRF validation when the matched endpoint opts in via IAntiforgeryMetadata.RequiresValidation == true, preventing previously-working endpoints (e.g., plain MapPost, unannotated [HttpPost]) from becoming newly blocked.

Changes:

  • Update CsrfProtectionMiddleware to skip validation unless the matched endpoint has IAntiforgeryMetadata { RequiresValidation: true }.
  • Adjust integration tests to explicitly attach RequireAntiforgeryTokenAttribute where tests intend to exercise the “validation runs” path, and add new tests covering “no metadata / opted out” pass-through behavior.
Show a summary per file
File Description
src/DefaultBuilder/src/Internal/CsrfProtectionMiddleware.cs Changes validation gating to require endpoint opt-in via IAntiforgeryMetadata.RequiresValidation == true.
src/DefaultBuilder/test/Microsoft.AspNetCore.Tests/CsrfProtectionIntegrationTests.cs Updates existing tests to opt endpoints in where needed and adds coverage for pass-through/no-verdict scenarios.

Copilot's findings

  • Files reviewed: 2/2 changed files
  • Comments generated: 1

Comment thread src/DefaultBuilder/src/Internal/CsrfProtectionMiddleware.cs
Comment thread src/DefaultBuilder/src/Internal/CsrfProtectionMiddleware.cs Outdated
@alexandercarlis2-dotcom alexandercarlis2-dotcom linked an issue Jun 30, 2026 that may be closed by this pull request
DeagleGross and others added 2 commits June 30, 2026 12:14
Split CsrfProtectionMiddleware.InvokeAsync into a synchronous wrapper
that sets the sentinel, checks endpoint metadata, and returns _next(context)
directly when validation is not required. The async core moves to a
private InvokeCoreAsync that handles the await chain only when an
endpoint opts in via IAntiforgeryMetadata { RequiresValidation: true }.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- EnforceCsrf now returns 'passthrough' | 'allowed' | 'protected' so
  body assertions disambiguate skip vs allow vs deny outcomes.
- Add EnforceCsrfProtected ([RequireAntiforgeryToken]) and EnforceCsrfForm
  ([FromForm]) helpers; replace .WithMetadata(new RequireAntiforgeryTokenAttribute())
  call sites that route through these handlers.
- CreateApp uses the new helpers and adds a /passthrough route (no metadata)
  exercising the alt-design skip path.
- Add CsrfProtection_RdfInferredFormMetadata_CrossOriginUntrustedOrigin_Protects
  to cover the RequestDelegateFactory InferAntiforgeryMetadata path.
- Add inline body assertions matching the new tri-state values.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@DeagleGross
DeagleGross merged commit 864a30a into dotnet:main Jun 30, 2026
25 checks passed
@DeagleGross
DeagleGross deleted the deaglegross-dmkorolev-csrf-skip-when-no-metadata branch June 30, 2026 12:04
javiercn pushed a commit that referenced this pull request Jun 30, 2026
…yMetadata` (#67460)

Aligns CsrfProtectionMiddleware with classic AntiforgeryMiddleware: validation runs only when the matched endpoint has IAntiforgeryMetadata { RequiresValidation: true }. Endpoints without metadata (plain MapPost, plain [HttpPost]) pass through, matching .NET 10 behavior — so no customer endpoint that worked on .NET 10 will start failing on .NET 11.

Blazor SSR and RDF form binding stay protected because they already attach RequireAntiforgeryTokenAttribute automatically. The MiddlewareInvokedKeys.CsrfProtection sentinel is still set unconditionally to preserve the FormFeature backstop contract from #67082.
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 11.0-preview7 milestone Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug This issue describes a behavior which is not expected - a bug. feature-antiforgery

Projects

None yet

6 participants