You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
AddControllersWithViews(options => options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute())) in Program.cs. Every unsafe MVC request is now validated by default. Razor Pages already validate by default. Behavior change for adopters: API actions called without cookies (bearer-token clients) need [IgnoreAntiforgeryToken]. None of the template's own actions are affected.
5. Claims types disagree between transformation and audit actor (MEDIUM)
HttpContextCurrentActorAccessorandHttpContextApplicationAuditContextAccessor (which had the same bug) now read application:subject first, then sub, then NameIdentifier. With RemoveOriginalClaims = true, authenticated users are attributed correctly instead of as Remote IP: ….
ApplicationClaimsTransformation now clones each identity and returns a new principal, so the incoming principal is never mutated.
Each transformed identity's NameClaimType / RoleClaimType is set to application:name / application:role, so User.Identity.Name, User.IsInRole and [Authorize(Roles = "...")] work. The original type is kept only when the identity still has claims of that type and no normalized equivalent (for example, an unmapped provider type), so existing checks don't silently break.
7. Structural / secure-default nits (LOW)
HSTS moved out of ErrorHandling/ProblemDetailsExtensions into SecurityHeadersExtensions.UseApplicationHsts(). It is called right after UseProblemDetails(), so the effective middleware order is unchanged. The docs, which wrongly said the pipeline doesn't call UseHsts(), now match the code.
SectionName on ApplicationSecurityHeadersOptions and ApplicationRequestLoggingOptions is now const.
Excluded paths (/health, /metrics) now still get X-Content-Type-Options: nosniff. They still skip the other headers.
Authorization policies are now built in Configure<IOptions<ApplicationAuthorizationOptions>> from the bound, validated options instance. The separate configuration.Get<>() snapshot is gone. Note: policies are still materialized once, when AuthorizationOptions is first resolved, so they are not reload-aware.
Tests
New AntiforgeryTests: a POST without an antiforgery attribute returns 400 without a token and 200 with one.
ClaimsTransformationTests: the incoming principal is not mutated, and IsInRole and Identity.Name work after RemoveOriginalClaims.
HttpContextCurrentActorAccessorTests: the normalized subject is used on its own and preferred over sub.
Updated excluded-path tests to expect nosniff only.
…efaults
- Register AutoValidateAntiforgeryTokenAttribute globally for MVC.
- Audit actor and audit context accessors read application:subject first,
so RemoveOriginalClaims no longer degrades actors to "Remote IP: ...".
- Claims transformation returns a new principal instead of mutating the
incoming one, and sets NameClaimType/RoleClaimType to application:name and
application:role so IsInRole and [Authorize(Roles)] work.
- Move HSTS registration from the error-handling extension to
UseApplicationHsts() in SecurityHeadersExtensions (same pipeline position).
- Make ApplicationSecurityHeadersOptions/ApplicationRequestLoggingOptions
SectionName const.
- Excluded paths (/health, /metrics) still receive X-Content-Type-Options.
- Build authorization policies from the validated options instance rather
than a registration-time configuration snapshot.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CodeQL (cs/web/missing-token-validation) cannot see globally registered MVC
filters and flagged the intentionally unannotated POST test action. Exercise
the global AutoValidateAntiforgeryTokenAttribute through an unannotated PUT
instead, which the filter covers and the rule does not target.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This change fixes normalized-subject precedence in the audit accessor, but the test suite has no test that resolves HttpContextApplicationAuditContextAccessor.Current (the added actor tests cover only HttpContextCurrentActorAccessor). A regression here could still silently record authenticated requests as remote-IP actors; add focused coverage for normalized-only and normalized-versus-sub claims.
Add integration coverage for the non-Development HSTS header
The new non-Development HSTS registration is not asserted by the integration suite: the factory uses the Testing environment and these clients use HTTPS, but no test checks Strict-Transport-Security. Add a focused response assertion so moving or accidentally removing this security middleware cannot pass without detection.
Clarify health response header behavior with HSTS
docs/articles/health-checks.md:125
This description says health responses receive only X-Content-Type-Options, but UseApplicationHsts() is still applied to HTTPS health responses outside Development. Qualify the statement to the configurable security-header middleware or document the separate HSTS header, otherwise the health-check contract is misleading.
Clarify excluded-path security header behavior with HSTS
docs/articles/security-headers.md:29
UseApplicationHsts() runs before this middleware for every non-Development HTTPS request, including excluded paths, so those responses can also contain Strict-Transport-Security. Saying excluded paths receive no other security header conflicts with the HSTS contract documented immediately below; qualify this statement as applying to headers emitted by SecurityHeadersMiddleware, or mention the separately registered HSTS header.
Registering UseApplicationHsts() from the pipeline after UseProblemDetails()
moved HSTS behind the status-code UseWhen branches, so status-code
re-execution could invoke it again. UseProblemDetails() now calls
UseApplicationHsts() in the original slot, between the exception handler and
the status-code branches. The implementation stays in SecurityHeadersExtensions.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…h docs
- Add HstsTests: the application pipeline emits Strict-Transport-Security
outside Development, and UseApplicationHsts emits it in Production and not
in Development. This restores SecurityHeadersExtensions branch coverage
above the security-critical 60% floor.
- Add HttpContextApplicationAuditContextAccessorTests for normalized-only,
normalized-versus-sub, provider-only, and remote-IP fallback resolution.
- Qualify the excluded-path statements in security-headers.md and
health-checks.md: they describe the security header middleware, and
HSTS is registered separately and still applies outside Development.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
4. Global antiforgery filter (MEDIUM)
AddControllersWithViews(options => options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()))inProgram.cs. Every unsafe MVC request is now validated by default. Razor Pages already validate by default.Behavior change for adopters: API actions called without cookies (bearer-token clients) need
[IgnoreAntiforgeryToken]. None of the template's own actions are affected.5. Claims types disagree between transformation and audit actor (MEDIUM)
HttpContextCurrentActorAccessorandHttpContextApplicationAuditContextAccessor(which had the same bug) now readapplication:subjectfirst, thensub, thenNameIdentifier. WithRemoveOriginalClaims = true, authenticated users are attributed correctly instead of asRemote IP: ….ApplicationClaimsTransformationnow clones each identity and returns a new principal, so the incoming principal is never mutated.NameClaimType/RoleClaimTypeis set toapplication:name/application:role, soUser.Identity.Name,User.IsInRoleand[Authorize(Roles = "...")]work. The original type is kept only when the identity still has claims of that type and no normalized equivalent (for example, an unmapped provider type), so existing checks don't silently break.7. Structural / secure-default nits (LOW)
ErrorHandling/ProblemDetailsExtensionsintoSecurityHeadersExtensions.UseApplicationHsts(). It is called right afterUseProblemDetails(), so the effective middleware order is unchanged. The docs, which wrongly said the pipeline doesn't callUseHsts(), now match the code.SectionNameonApplicationSecurityHeadersOptionsandApplicationRequestLoggingOptionsis nowconst./health,/metrics) now still getX-Content-Type-Options: nosniff. They still skip the other headers.Configure<IOptions<ApplicationAuthorizationOptions>>from the bound, validated options instance. The separateconfiguration.Get<>()snapshot is gone. Note: policies are still materialized once, whenAuthorizationOptionsis first resolved, so they are not reload-aware.Tests
AntiforgeryTests: a POST without an antiforgery attribute returns 400 without a token and 200 with one.ClaimsTransformationTests: the incoming principal is not mutated, andIsInRoleandIdentity.Namework afterRemoveOriginalClaims.HttpContextCurrentActorAccessorTests: the normalized subject is used on its own and preferred oversub.nosniffonly.dotnet build -c Release(warnings as errors) passes;dotnet test: 462/462 passed.🤖 Generated with Claude Code