Join our Newsletter — 33% off our NHI Course
Home› Guides› .NET Security Guide: ASP.NET Core, NuGet and Secrets…
Guide Application Security

.NET Security Guide: ASP.NET Core, NuGet and Secrets Handling

PDF for newsletter subscribers · free to read online

← All guides
By Lalit Choda, NHI Mgmt Group Updated 24 October 2026 17 min read
On this page

Most serious .NET compromises do not come from the runtime itself but from what teams configure around it: leaked or copied machine keys, unsafe deserialisers, secrets in appsettings files, permissive CORS and long-lived NuGet publishing keys. The platform has moved a long way: ASP.NET Core replaced the <machineKey> model with the Data Protection API, .NET 9 removed the working BinaryFormatter, NuGet now audits dependencies on restore, and nuget.org supports OIDC-based Trusted Publishing. This guide covers the settings and patterns that matter in ASP.NET Core and legacy ASP.NET, how to handle secrets and machine identities, and how to secure the NuGet supply chain in both directions. It is for .NET developers, AppSec engineers and platform teams.

Key takeaways

  • Check your runtime support date now: .NET 8 (LTS) and .NET 9 (STS) both leave support on 10 November 2026; .NET 10 (LTS) is supported to 14 November 2028.
  • Key material is an identity: ASP.NET machine keys and Data Protection key rings sign cookies and ViewState, so a stolen or copied key lets an attacker forge trusted state and, for ViewState, run code.
  • Deny by default in authorisation: set a fallback policy that requires an authenticated user and mark public endpoints with [AllowAnonymous], rather than relying on every new controller remembering [Authorize].
  • Replace connection-string passwords with managed identities: in Azure, a managed identity with ManagedIdentityCredential removes the stored secret entirely; user-secrets are for development only and are not encrypted.
  • Lock down NuGet both ways: consume with NuGet Audit, package source mapping and lock files, and publish with Trusted Publishing, because nuget.org API keys created before 17 August 2026 expire on 1 November 2026.

Supported versions and patching

Running an unsupported runtime means no security fixes for the runtime, ASP.NET Core or the base class libraries. Microsoft publishes the support policy on the .NET website; long-term support (LTS) releases get three years of patches and standard-term support (STS) releases get two, with end-of-support dates aligned to Patch Tuesday.

VersionTypeReleasedEnd of supportAction as of October 2026
.NET 10LTS11 November 202514 November 2028Target for all new and migrated workloads
.NET 9STS12 November 202410 November 2026Migrate to .NET 10 immediately
.NET 8LTS14 November 202310 November 2026Migrate to .NET 10 immediately
.NET 7, 6 and earlierSTS / LTS2022 and earlierAlready ended (.NET 6 on 12 November 2024)Treat as an unpatched asset; isolate and replace
  • Patch the runtime, not just packages: self-contained deployments and container images embed the runtime, so they must be rebuilt to pick up a fix. Framework-dependent apps take the fix from the host's installed runtime.
  • Track container base images: pin a supported tag such as a 10.0 runtime image and rebuild on each monthly servicing release.

Authentication and authorisation in ASP.NET Core

ASP.NET Core supplies strong building blocks, but its defaults assume you will opt endpoints in to protection. The most reliable pattern is to invert that.

  • Fallback policy: Microsoft's documentation describes the fallback policy as the preferred way to require all users to be authenticated, because it protects newly added Razor Pages and controllers automatically. The policy applies whenever an endpoint has no authorisation metadata.
  • Explicit public endpoints: use [AllowAnonymous] (or .AllowAnonymous() on minimal API endpoints) for login, health and landing pages, and review that list in code review.
  • Resource-based checks: attributes cannot see the object being accessed. Use IAuthorizationService.AuthorizeAsync(User, resource, requirement) in the handler for per-record rules, which is where broken object-level authorisation (CWE-639, OWASP API1) usually creeps in.
  • Middleware order: UseRouting, then UseCors, then UseAuthentication and UseAuthorization, then endpoint mapping. Placing static files or custom middleware before authorisation can expose content unintentionally.
builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

For service-to-service APIs, validate JWT audience, issuer and lifetime explicitly and prefer short-lived tokens from your identity provider over shared API keys. See the NHI Authentication Guide.

Data Protection API and machine keys

The ASP.NET Core Data Protection API replaces the <machineKey> element from ASP.NET 4.x. It protects authentication cookies, antiforgery tokens, TempData and anything else your code round-trips through the browser. By default keys have a 90-day lifetime, new keys are generated automatically, and retired keys stay in the ring so older payloads can still be read. Payloads use AES-256-CBC with HMACSHA256, derived from a 512-bit master key.

Hosting environmentDefault key locationEncrypted at rest by defaultWhat to do
Azure App Service%HOME%\ASP.NET\DataProtection-Keys, one ring per slotNoUse an external ring (Blob Storage plus Key Vault) so slot swaps do not log users out, and protect keys with a Key Vault key
IIS with user profile%LOCALAPPDATA%\ASP.NET\DataProtection-KeysYes, DPAPIKeep setProfileEnvironment true; share the ring across a farm
IIS without profileHKLM registry, ACL'd to the worker processYes, DPAPIAcceptable for a single server; farms need shared storage
Containers and KubernetesNone matched: keys held in memory onlyNot applicablePersist to a volume or external provider, otherwise every restart invalidates cookies
Custom repository (PersistKeysTo*)Where you point itNo, automatic encryption is disabledAdd ProtectKeysWith* (certificate or Key Vault key)
  • Set an application name: every instance in a farm must share the ring and call SetApplicationName with the same value; different apps should not share a ring.
  • Do not delete keys casually: Microsoft warns that deleting a key makes data it protected permanently unreadable. Revoke a suspected-compromised key instead, which forces a new active key.
  • Not for long-term storage: the API is designed for transient protected payloads. For data that must stay encrypted for years, use envelope encryption with a key management service. See the Cryptographic Key Management Guide.

Legacy ASP.NET machine keys and ViewState

In ASP.NET 4.x Web Forms, the ValidationKey signs ViewState and the DecryptionKey encrypts it. Anyone holding those values can craft a ViewState payload the server will deserialise, which is remote code execution on IIS. In February 2025 Microsoft Threat Intelligence reported more than 3,000 publicly disclosed machine keys, copied from documentation and code repositories, and an attacker using one to load the Godzilla post-exploitation framework. See the ASP.NET machine key attacks write-up.

  • Generate, never copy: create keys per application or farm with IIS Manager or Microsoft's script, or remove a fixed <machineKey> element so keys are auto-generated on single servers.
  • Encrypt configuration sections: Microsoft recommends encrypting machineKey and connectionStrings in web.config during deployment.
  • Upgrade to .NET Framework 4.8 for Antimalware Scan Interface (AMSI) support, and enable the attack surface reduction rule that blocks web shell creation on servers.
  • Rotation is not remediation: rotating keys does not remove an implant already installed. If a public or stolen key was in use, investigate the host and consider rebuilding it.

Deserialisation and other dangerous APIs

Microsoft's own guidance says calling BinaryFormatter.Deserialize on a payload is roughly equivalent to running that payload as an executable, and that no SerializationBinder configuration fully mitigates it. From .NET 9 the in-box BinaryFormatter throws on use and the compatibility switches have been removed. The same unrestricted polymorphic risk applies to SoapFormatter, LosFormatter, NetDataContractSerializer and ObjectStateFormatter, which is why ViewState with a known key leads to code execution. See the Insecure Deserialisation Guide.

API or patternRiskSafer alternative
BinaryFormatter, SoapFormatter, NetDataContractSerializerType-controlled deserialisation, RCE (CWE-502)System.Text.Json into concrete types; DataContractSerializer or XmlSerializer with known types
LosFormatter, ObjectStateFormatter (ViewState)RCE when machine key is knownUnique keys, MAC validation on, migrate off Web Forms
Json.NET with TypeNameHandling other than NoneAttacker-chosen types from $typeKeep TypeNameHandling.None, or a strict allow-list binder
String-built SQL with FromSqlRaw or SqlCommandSQL injection (CWE-89)Parameters, FromSql with interpolated parameters, LINQ
Html.Raw, MarkupString on user dataCross-site scripting (CWE-79)Default Razor encoding; sanitise if HTML is genuinely needed
Process.Start with user inputOS command injection (CWE-78)Use ProcessStartInfo.ArgumentList, never a shell, and an allow-list

Enable the built-in .NET analysers (<AnalysisMode>All</AnalysisMode> or at least the security rules) and fail the build on new security warnings. Many of the patterns above have dedicated CA rules. See the CWE Top 25 Guide.

Browser-facing protections: antiforgery, CORS and errors

Antiforgery

  • Razor Pages are protected automatically; MVC needs AddControllersWithViews (not AddControllers alone) and a global AutoValidateAntiforgeryTokenAttribute, which skips GET, HEAD, OPTIONS and TRACE.
  • Minimal APIs: call AddAntiforgery() and UseAntiforgery() after authentication and authorisation. The middleware validates only POST, PUT and PATCH; call IAntiforgery.ValidateRequestAsync for DELETE handlers that use cookies.
  • Watch method override: HttpMethodOverrideMiddleware in form-field mode placed before antiforgery can turn a POST into a DELETE that skips validation.

CORS

Microsoft's documentation is explicit that CORS relaxes the same-origin policy and is not a security feature. Configure the narrowest named policy with exact origins (no trailing slash). AllowAnyOrigin with AllowCredentials is rejected by the CORS service, and the common workaround SetIsOriginAllowed(_ => true) with AllowCredentials is equally insecure: it lets any site make credentialed requests and read responses. Be careful with SetIsOriginAllowedToAllowWildcardSubdomains where any subdomain can be taken over.

Errors, debugging and tracing

  • ASP.NET Core: the developer exception page should only run when app.Environment.IsDevelopment(); production uses UseExceptionHandler and problem details without stack traces. Never set ASPNETCORE_ENVIRONMENT=Development on a production host.
  • Legacy ASP.NET: in web.config set <compilation debug="false">, <trace enabled="false"> (otherwise trace.axd can expose request data and session values), and <customErrors mode="RemoteOnly"> or On. Use <deployment retail="true"> in machine.config on production servers to force these off.
  • HTTPS and HSTS: use UseHttpsRedirection and UseHsts for browser apps; for APIs, reject plain HTTP rather than redirecting, because redirects break CORS preflight.

Secrets and machine identities

.NET configuration layers make it easy to put a secret anywhere: appsettings.json, environment variables, command-line arguments, user-secrets or a vault. Choose by environment, not by convenience.

MechanismEncryptedUse forNotes
appsettings.jsonNoNon-secret settings onlyChecked into source control; scan with secret detection
Secret Manager (dotnet user-secrets)NoLocal developmentStored in the user profile, outside the repo; Microsoft states it is not a trusted store
Environment variablesNoContainer and platform injectionPlain text, visible to process dumps and diagnostics; use __ as the separator
Azure Key Vault configuration providerYesProduction secrets that must existSecrets are cached for the app lifetime unless ReloadInterval is set; expired secrets still load by default
Managed identity (no secret)Not applicableAzure SQL, Storage, Service Bus, Key Vault and other Entra-integrated servicesRemoves the password from the connection string altogether

Where identity fits

A connection string with User ID and Password is a long-lived non-human credential that ends up in config files, deployment logs and memory dumps. In Azure, a managed identity gives the app an Entra ID service principal whose credentials are never exposed to you; the app requests tokens through Azure.Identity. Microsoft's Key Vault provider guidance recommends DefaultAzureCredential for development convenience and ManagedIdentityCredential in production, which avoids the credential chain silently picking up a developer or environment credential.

  • System-assigned versus user-assigned: system-assigned identities are deleted with the resource and cannot be shared; user-assigned identities live independently and suit several instances or frequently recycled resources. Microsoft recommends user-assigned for its own services. Either way, assign least-privilege RBAC roles and review them like any other privileged account. See the Azure RBAC and Service Principals Guide.
  • Outside Azure: use workload identity federation (for example from Kubernetes or GitHub Actions) or a certificate credential, not a client secret. See the Workload Identity Federation Guide.
  • Machine keys and Data Protection keys belong in the same inventory: give each an owner, a storage location and a rotation rule. See the Secrets Management Guide.
// SQL with a managed identity: no password in the connection string
"Server=tcp:contoso.database.windows.net;Database=orders;Authentication=Active Directory Managed Identity;Encrypt=True"

NuGet supply chain: consuming packages

ControlSettingThreat addressed
NuGet AuditNuGetAudit (on by default since the .NET 8 SDK and NuGet 6.8), NuGetAuditMode (default all for net10.0 and later, direct otherwise), NuGetAuditLevelKnown-vulnerable direct and transitive packages, using the GitHub Advisory Database for nuget.org
Fail on severityWarningsAsErrors with NU1903;NU1904 (high, critical) in a CI audit pipelineVulnerable packages reaching release builds
Package source mapping<packageSourceMapping> in nuget.config with <clear /> on sources, prefix patterns such as Contoso.*Dependency confusion between internal and public feeds
Central Package ManagementDirectory.Packages.props, ManagePackageVersionsCentrally, CentralPackageTransitivePinningEnabledVersion drift; lets you pin a patched transitive package
Lock filesRestorePackagesWithLockFile and dotnet restore --locked-mode in CIUnreviewed dependency changes at build time
Signature validationsignatureValidationMode=require with trustedSigners (author or repository, optional owners)Packages from untrusted signers; tampering fails with NU3008
  • Source mapping caveat: packages already in the global packages folder bypass mapping, so use a per-repository packages folder in CI. Commands such as dotnet list package --vulnerable still query every configured source.

See the Malicious Package and Dependency Confusion Guide and the Software Supply Chain Security Guide.

NuGet supply chain: publishing packages

If your organisation publishes to nuget.org, the publishing key is the most valuable credential in the project: whoever holds it can ship code to every consumer. Microsoft announced Trusted Publishing for nuget.org on 22 September 2025. A GitHub Actions or GitLab CI/CD job requests an OIDC token, nuget.org validates it against a policy (repository owner, repository, workflow file and optional environment) and returns a temporary API key valid for one hour. Each OIDC token yields exactly one key.

  • Deadline: on 3 August 2026 Microsoft announced that new nuget.org API keys are limited to 30 days from 17 August 2026, and that keys created before that date expire on 1 November 2026. Any pipeline still using an old key will stop publishing then.
  • Bind to an environment: require a protected GitHub environment such as release in the policy, so only reviewed release jobs can obtain a key.
  • Least privilege in the workflow: grant id-token: write only to the publishing job, not the whole workflow.
  • Resurrection protection: new policies are temporarily active for 7 days until a first publish records the repository and owner IDs, which stops a deleted repository being recreated under the same name to inherit the policy.
  • Sign what you ship: author-sign packages with a code signing certificate so consumers can pin your fingerprint. See the Code Signing Security Guide and the CI/CD Pipeline Identity Security Guide.
jobs:
  publish:
    environment: release
    permissions:
      id-token: write
    steps:
      - uses: NuGet/login@v1
        id: login
        with:
          user: ${{ secrets.NUGET_USER }}
      - run: dotnet nuget push out/*.nupkg --api-key ${{ steps.login.outputs.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json

Rolling out a .NET security baseline

  1. Inventory: list every application with its target framework, hosting model, and whether it is ASP.NET Core or .NET Framework. Flag anything on .NET 8 or 9 for migration before 10 November 2026.
  2. Find exposed keys and secrets: search repositories and web.config files for <machineKey, Password= and AccountKey=; check machine keys against Microsoft's published hashes of disclosed keys.
  3. Enable build-time checks in warning mode: NuGet Audit with NuGetAuditMode=all, .NET security analysers and secret scanning. Run for two sprints to measure the backlog.
  4. Apply platform defaults in a shared template: fallback authorisation policy, antiforgery filter, strict CORS policy, production exception handling, external Data Protection ring.
  5. Move to managed identities: pilot one service per team, removing the password from its connection string, then retire the old secret after a week with no fallback use.
  6. Switch the gates to blocking: fail CI on NU1903/NU1904 and on new high-severity analyser findings; adopt lock files and source mapping.
  7. Migrate publishing to Trusted Publishing and delete the old API keys.
  8. Rollback: keep each change in configuration (MSBuild properties, nuget.config, policy registration) so it can be reverted per repository; for Data Protection moves, import the old key ring into the new store first so existing cookies stay valid.

Detection and measurement

  • IIS and app logs: alert on w3wp.exe spawning cmd.exe or PowerShell, new .aspx files in web roots, and ViewState MAC validation failures (event 1316 in the Application log on .NET Framework) in bursts.
  • Defender signals: Microsoft Defender for Endpoint raises "Publicly disclosed ASP.NET machine key" and "IIS worker process loaded suspicious .NET assembly" alerts.
  • Identity logs: managed identity sign-ins appear in Entra ID sign-in logs; alert on a managed identity used from an unexpected resource or calling an unusual service.
MetricTarget
Applications on a supported .NET runtime100% after 10 November 2026
Builds with NuGet Audit in all mode and blocking on high/critical100% of release pipelines
Open high or critical NuGet advisories older than 30 daysZero, or a recorded suppression
Azure workloads authenticating with a managed identity rather than a stored secretRising each quarter
Fixed <machineKey> values found in source controlZero
nuget.org packages published via Trusted Publishing100% before 1 November 2026

Framework mapping

AreaNIST SP 800-53 Rev. 5NIST CSF 2.0ISO/IEC 27001:2022 Annex AMITRE ATT&CK
Secure development and analysersSA-11, SA-15PR.PS-06A.8.25, A.8.28T1190 Exploit Public-Facing Application
Machine keys and Data ProtectionSC-12, SC-28PR.PS-06A.8.24T1505.003 Web Shell
Secrets and managed identitiesIA-5PR.PS-06A.8.24T1552.001 Credentials In Files
NuGet consumption and publishingSR-3, SR-4ID.RA-01A.8.25T1195.001, T1195.002
Runtime patching and debug settingsSI-2, CM-7ID.RA-01A.8.28T1190

In CIS Controls v8.1 this work sits mainly in Control 16 (Application Software Security). See the Secure Coding Guide.

Common failure patterns

  • Copied machine keys: a <machineKey> block pasted from a forum or sample ships to production, giving anyone who reads the sample the means to forge ViewState. This is the pattern behind the ASP.NET machine key attacks.
  • Patching without rotating: in the ToolShell SharePoint exploitation of July 2025, a web shell read the server's ValidationKey and DecryptionKey, so attackers could keep signing malicious ViewState after the CVE-2025-53770 fix until keys were rotated and IIS restarted. See the SharePoint and OneDrive Security Guide.
  • Credentialed wildcard CORS: SetIsOriginAllowed(_ => true) plus AllowCredentials added to "fix" a front-end error, exposing every authenticated API response to any website.
  • Ephemeral key rings in containers: Data Protection keys held in memory, so every redeploy logs users out; teams then "fix" it by baking a static key file into the image, which leaks with the image.
  • Secrets in configuration history: a connection string with a password committed to appsettings.Production.json, removed later but still in git history and old build artefacts.
  • Long-lived publishing keys in CI variables: a 365-day nuget.org key with push rights to all packages, shared across repositories, which is exactly what Trusted Publishing removes.

Practitioner checklist

  • Migrate every .NET 8 and .NET 9 application to .NET 10 before 10 November 2026 and rebuild container images monthly.
  • Set a fallback authorisation policy requiring authenticated users and review every [AllowAnonymous].
  • Persist Data Protection keys to shared, encrypted storage with an explicit application name.
  • Remove fixed or copied <machineKey> values, generate unique keys, and encrypt the section in web.config.
  • Eliminate BinaryFormatter and related formatters; deserialise only into known types with System.Text.Json.
  • Replace connection-string passwords with managed identities and use ManagedIdentityCredential in production.
  • Enable NuGet Audit in all mode, package source mapping, lock files and blocking on NU1903/NU1904.
  • Move nuget.org publishing to Trusted Publishing before old API keys expire on 1 November 2026.
  • Configure CORS with explicit origins only and never combine permissive origins with credentials.
  • Monitor for w3wp.exe child processes and new web files, and rotate keys after any web shell finding.

Standards and references

Related NHI Mgmt Group resources: Secure Coding Guide · Software Supply Chain Security Guide · Secrets Management Guide · Insecure Deserialisation Guide · Java and Spring Security Guide

PDF for subscribers

Take this guide with you

Every section, table and checklist in one PDF, with links to the sources and related guides. Subscribe to our weekly NHI & AI Identity Journal and we’ll email you a download link.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Written and reviewed by Lalit Choda, NHI Mgmt Group. Last updated 24 October 2026.
NHI Mgmt Group — the #1 independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org

PDF Downloads for Newsletter Subscribers

Get the guide

Enter your details and we’ll email you a download link.

The full guide is free to read online. The PDF is a thank you for subscribing.

Fill in all fields marked * and tick the PDF box to continue.