Fix cards for C# and ASP.NET Core

A01:2025 Broken Access Control

  • Cross-site request forgery (CSRF)CWE-352

    Call AddAntiforgery() and, after UseAuthentication() and UseAuthorization(), UseAntiforgery().

  • Missing object-level authorization (IDOR and BOLA)CWE-862 · CWE-639 · CWE-863

    Read the user's ID, tenant and role from the ClaimsPrincipal your authentication scheme builds, never from the request, and scope every invoice query with tenant_id = $tenant AND (owner_id = $user OR $isBillingAdmin).

  • Open redirectCWE-601

    Check Url.IsLocalUrl(returnUrl) and redirect with LocalRedirect(returnUrl): IsLocalUrl accepts "/" or "~/" paths not followed by "/" or "\" and free of control characters.

  • Path traversalCWE-22 · CWE-23 · CWE-36 · CWE-59

    Use Path.GetFullPath(name, baseDir) and serve the result only if it starts with the base plus a trailing separator, compared with StringComparison.Ordinal.

  • Server-side request forgery (SSRF)CWE-918

    Attach the policy to the connection, not the hostname string.

A02:2025 Security Misconfiguration

  • CORS misconfiguration on credentialed APIsCWE-942 · CWE-346

    Add a named CORS policy with WithOrigins(allowedOrigins) from configuration and AllowCredentials(), call app.UseCors(), and require the policy on the API endpoints.

  • XML external entity (XXE) processingCWE-611 · CWE-776

    On .NET, parse untrusted XML with XmlReaderSettings.DtdProcessing = Prohibit and XmlResolver = null (both the modern defaults), so any DOCTYPE throws before an external entity is read (CWE-611) or entities expand (CWE-776).

A04:2025 Cryptographic Failures

  • Insecure randomness for security tokensCWE-330 · CWE-338

    Generate the token with RandomNumberGenerator.GetBytes(32) (256 bits), Base64Url-encoded.

  • Weak password hashingCWE-916 · CWE-759 · CWE-327

    Use ASP.NET Core Identity's PasswordHasher<TUser> (PBKDF2-HMAC-SHA512, 128-bit salt) with PasswordHasherOptions.IterationCount = 220_000; .NET 10's default of 100,000 is below OWASP's figure.

A05:2025 Injection

  • Code injectionCWE-94 · CWE-95

    Do not run request input as code. Roslyn's CSharpScript executes the formula with the server's privileges, and a denylist of dangerous APIs cannot make it safe: it misses Environment.GetEnvironmentVariable and is never complete.

  • Cross-site scripting (XSS)CWE-79

    Let Razor's @ encode the output: @Model.Name and @Model.Bio HTML-encode & < > " ' and more, in text and in a quoted attribute.

  • CSV formula injectionCWE-1236

    Spreadsheets run a cell that starts with =, +, -, @, tab or carriage return.

  • OS command and argument injectionCWE-78 · CWE-88

    Start the process with ProcessStartInfo.ArgumentList and UseShellExecute = false - psi.ArgumentList.Add("--"); psi.ArgumentList.Add(name) - so no shell parses the arguments, and the '--' makes a leading-dash operand data, not an option.

  • Server-side template injectionCWE-1336 · CWE-94 · CWE-95

    Don't run user input as code: CSharpScript.EvaluateAsync compiles the 'template' as C#.

  • SQL injectionCWE-89

    Keep CommandText constant and bind values: write $name placeholders and call command.Parameters.AddWithValue("$name", name).

  • XPath injectionCWE-643 · CWE-91

    Parameterize the query: compile the XPath with $username and $password variables and supply them through a custom XsltContext (ResolveVariable returning an IXsltContextVariable), attached with XPathExpression.SetContext.

A06:2025 Insecure Design

  • Regular-expression denial of service (ReDoS)CWE-1333

    A validation regex with a nested quantifier backtracks catastrophically on the default engine: a 30-character string pins the request thread.

  • Unbounded resource consumptionCWE-770 · CWE-400

    Bound every resource a request can consume: read the body with a byte cap (413 over it), cap the batch size (400 over it), and add the rate limiter (AddRateLimiter, a fixed window) keyed on the connection address, not a client header.

  • Unrestricted file uploadCWE-434 · CWE-646 · CWE-73 · CWE-770

    Decide the type from the bytes, and never let the client pick the name.

A07:2025 Authentication Failures

  • Hard-coded secretsCWE-798 · CWE-260

    Bind the key with AddOptions<T>().BindConfiguration("Forecast"), mark it [Required] and call ValidateDataAnnotations() and ValidateOnStart() so a missing or blank key stops the app at startup.

  • Improper TLS certificate validationCWE-295 · CWE-297 · CWE-296

    Never return true from a certificate validation callback. Leave validation to SslStream and change only the trust anchor: set SocketsHttpHandler.SslOptions.CertificateChainPolicy to CustomRootTrust with the partner's CA in CustomTrustStore, and RevocationMode NoCheck if the private CA has no CRL.

  • JWT validation in APIs (bearer tokens)CWE-347 · CWE-287

    Configure JwtBearer's TokenValidationParameters with the issuer's signing key from configuration (or options.Authority), ValidAlgorithms = [RS256], ValidIssuer, ValidAudience and a ClockSkew of seconds, leaving ValidateIssuer, ValidateAudience, ValidateLifetime, RequireExpirationTime and RequireSignedTokens true.

  • Missing authentication for a critical functionCWE-306 · CWE-287

    Verify a credential on the server in your authentication handler, then require it on every protected endpoint.

  • Session fixation and session cookiesCWE-384 · CWE-613 · CWE-614 · CWE-1004 · CWE-1275

    Keep the signed-in user in an authentication cookie, not in ISession, which cannot change its ID: SignInAsync issues a new ticket at sign-in.

A08:2025 Software or Data Integrity Failures

  • Insecure deserializationCWE-502

    Do not let the payload choose the type. With Newtonsoft.Json keep TypeNameHandling at None and bind to a concrete class; a SerializationBinder blocklist is not enough and even quiets the analyzer.

  • Mass assignment (over-posting)CWE-915

    Bind the body to an input model record that declares only the fields users may edit (here ProfileUpdate(DisplayName, Bio)), never to the entity, and copy those fields onto the entity yourself.

Not covered in C# yet

These weaknesses have fix cards in other stacks but not in this one.

Supported versions

ASP.NET Core ships with .NET: LTS releases get three years of patches and STS releases two years, and you must stay on the latest patch to be supported. ASP.NET Core support policy.

ASP.NET Core
VersionLatestStatusReleasedEnd of support
10.0 (LTS)10.0.12SupportedThe cards use it.11 November 202514 November 2028
9.0 (STS)9.0.20MaintenanceSecurity fixes end on 2026-11-10; move to .NET 10.12 November 202410 November 2026
8.0 (LTS)8.0.31MaintenanceSecurity fixes end on 2026-11-10; move to .NET 10.14 November 202310 November 2026
.NET SDK
VersionLatestStatusReleasedEnd of support
10.010.0.401SupportedThe cards were built with SDK 10.0.112 and run on runtime 10.0.12.11 November 202514 November 2028
9.09.0.318MaintenanceSupport ends with .NET 9 on 2026-11-10.12 November 202410 November 2026
8.08.0.425MaintenanceSupport ends with .NET 8 on 2026-11-10.14 November 202310 November 2026

Build with the SDK band of the runtime you deploy; .NET 11 is a go-live release candidate, not a supported release. .NET SDK release schedule

How the fix cards choose versions

Minimum secure versions

The lowest release in each supported line that fixes every published advisory listed here. Anything older is missing a security fix.

PackageAt leastWhy
.NET runtime and Microsoft.AspNetCore.App10.0.12, 9.0.20 or 8.0.31The 8 September 2026 servicing releases, the latest on 11 October 2026: an ASP.NET Core denial of service under IIS out-of-process hosting (CVE-2026-69304) and three .NET and Visual Studio CVEs (CVE-2026-69439, CVE-2026-69522, CVE-2026-71328). Advisory
.NET SDK10.0.112 or 10.0.401, 9.0.121 or 9.0.318, or 8.0.131 or 8.0.425These SDKs carry the patched runtimes and the dotnet watch fixes for CVE-2026-58649 and, on Linux, CVE-2026-69806. Advisory

Middleware and security order

  1. Forwarded headers: UseForwardedHeaders with KnownProxies or KnownNetworks before other middleware and before UseHsts, so the scheme and client address come from your proxy.
  2. Exception handler, HSTS, HTTPS redirection: UseExceptionHandler first so it catches what follows, then UseHsts and UseHttpsRedirection; the developer exception page only in Development.
  3. Static files, then routing: UseStaticFiles (or MapStaticAssets) and UseRouting.
  4. CORS: UseCors before UseAuthentication and UseAuthorization.
  5. Authentication, authorization, antiforgery: UseAuthentication, UseAuthorization, then UseAntiforgery, which must come after both.
  6. Endpoints: Map endpoints with RequireAuthorization() or a fallback policy, and check resource ownership in the handler.

Secure defaults and settings

SettingValueWhy
Razor outputHTML-encodedKeep Html.Raw out of user data.
AntiforgeryValidated for Razor forms, and for minimal API form posts when UseAntiforgery is in the pipelineDo not add DisableAntiforgery() to cookie-authenticated form endpoints.
Cookie authentication cookieHttpOnly, SameSite=Lax, SecurePolicy same as requestSet CookieSecurePolicy.Always.
UseHsts max-age30 daysSet MaxAge to at least a year once HTTPS works everywhere; HSTS is not sent for localhost.
JWT bearer ClockSkew5 minutesReduce it to seconds.

Escape hatches to search for

Framework APIs that switch a protection off. Each one is sometimes needed; search for them in review and make each use justify itself.

APIRiskInstead
Html.Raw()Unencoded output.Encoded output, or a sanitizer for HTML you must render.
[IgnoreAntiforgeryToken] or DisableAntiforgery()CSRF on cookie-authenticated endpoints.Keep antiforgery on form endpoints that use cookies.
[AllowAnonymous]Overrides the authorization policy, including a fallback policy.Use it only on deliberately public endpoints.
Newtonsoft.Json TypeNameHandling other than NoneThe payload chooses the types to create.System.Text.Json or known types.
ValidateIssuer = false, ValidateAudience = false, ValidateLifetime = falseAccepts tokens issued for another API, by another tenant or after expiry.Configure the authority and audience.
SetIsOriginAllowed(_ => true) with AllowCredentials()Any site can read authenticated responses.WithOrigins(...).
EF Core FromSqlRaw with an interpolated stringSQL injection.FromSql with an interpolated string, which EF turns into parameters.

Checklist, mapped to ASVS 5.0.0

  • v5.0.0-3.4.1 HSTS is on with a max-age of at least a year.
  • v5.0.0-3.5.1 Cookie-authenticated form posts validate an antiforgery token.
  • v5.0.0-8.2.1 A fallback authorization policy requires authenticated users.
  • v5.0.0-8.2.2 Handlers use resource-based authorization or owner-scoped queries.
  • v5.0.0-9.1.1 JWT bearer authentication validates the signature, issuer, audience and lifetime.
  • v5.0.0-1.2.4 EF Core and ADO.NET queries use parameters.
  • v5.0.0-4.1.3 Forwarded headers are accepted only from known proxies.
  • v5.0.0-16.5.1 UseExceptionHandler returns a generic problem response outside Development.

References

  1. ASP.NET Core middleware: middleware order
  2. Configure ASP.NET Core to work with proxy servers and load balancers
  3. Enforce HTTPS in ASP.NET Core (HSTS)
  4. Prevent cross-site request forgery in ASP.NET Core
  5. .NET and .NET Core support policy
  6. .NET 10.0.12 release notes

All fix cards