You applied the April Patch Tuesday updates, ran your deployment pipeline, and moved on with your week. Then, on 21 April, Microsoft dropped an emergency out-of-band release: .NET 10.0.7. Not a routine servicing update — an urgent patch for CVE-2026-40372, a CVSS 9.1 critical vulnerability in Microsoft.AspNetCore.DataProtection. The component that protects your authentication cookies, anti-forgery tokens, and any other secrets you feed through IDataProtector.Protect.

The short version: on every non-Windows platform, the managed authenticated encryptor was computing its HMAC tag over the wrong bytes of the payload and then discarding the result. That meant the authentication step in "authenticated encryption" was not authenticating anything. An attacker who could intercept or inject a payload could forge cookies and escalate privileges without ever touching the encryption key.

If you run ASP.NET Core on Linux — which is to say, if you run it in Docker, on Azure App Service for Linux, on AWS, or on practically any cloud-native deployment — you need to patch immediately. Here is what went wrong, why, and how to verify you are safe.

The timeline

The story begins with the regular April 2026 Patch Tuesday release on 14 April. That update shipped .NET 10.0.6 with fixes for several CVEs, including SMTP header injection and XML recursion bombs. Business as usual.

Within days, users started reporting that their applications were throwing CryptographicException with the message "The payload was invalid" when trying to unprotect data that had been protected under 10.0.5. The decryption regression was tracked in aspnetcore#66335, and the stack traces pointed squarely at ManagedAuthenticatedEncryptor.CalculateAndValidateMac().

As the ASP.NET Core team investigated the regression, they discovered something worse: the regression was a symptom of a deeper bug that had been present since .NET 10.0.0. The HMAC validation in the managed encryptor had never been correct. The 10.0.6 servicing change merely shifted the failure mode from silently broken to loudly broken — and that loud failure is what exposed the underlying vulnerability.

How Data Protection authenticates payloads

Before diving into the bug, it helps to understand what a Data Protection payload looks like. When you call IDataProtector.Protect(plaintext), the system produces a byte array with this structure:

| Magic Header (4 bytes) | Key ID (16 bytes) | Key Modifier (16 bytes) | IV (16 bytes) | Ciphertext (variable) | HMAC Tag (32 bytes) |

The magic header and key ID identify which key ring entry to use. The key modifier feeds into a key derivation function (SP800-108 in CTR mode with HMAC-SHA512) to derive two subkeys: one for AES-256-CBC encryption and one for HMAC-SHA256 validation.

The critical part is the HMAC tag at the end. It is computed over the IV and ciphertext bytes only — not the key modifier, because the modifier is already mixed into the key derivation. During decryption, the system recomputes the HMAC over the same range and compares it using a time-constant comparison. If the tags do not match, the payload is rejected.

That is how it is supposed to work. The CNG-based encryptor on Windows has done this correctly since the Data Protection system was introduced. The managed encryptor, used everywhere else, had a different story.

The bug: HMAC over the wrong bytes

The ManagedAuthenticatedEncryptor class handles all authenticated encryption on non-Windows platforms. Its encrypt path is roughly:

  1. Generate a random key modifier and IV
  2. Derive encryption and validation subkeys from the master key + key modifier
  3. Encrypt the plaintext with AES-256-CBC
  4. Compute HMAC-SHA256 over the IV and ciphertext
  5. Assemble the payload: keyModifier | IV | ciphertext | hmacTag

Step 4 is where the bug lived. The managed encryptor was computing the HMAC over the wrong byte range of the output buffer. Instead of covering IV | ciphertext, the slice calculation was off — it was hashing a range that included parts of the key modifier or missed parts of the ciphertext, depending on the payload size. Worse, the computed hash was then written to a location that did not correspond to the HMAC tag field in the final payload, effectively discarding it.

The result: the HMAC tag in every payload produced by the managed encryptor was uninitialised or stale memory. And during decryption, the validation logic suffered from the same offset error, meaning it was checking the wrong bytes against the wrong tag. Two wrongs made a right — decryption "worked" because both sides were consistently wrong in the same way.

Example.cs
// Simplified illustration of the bug (not actual source)
// The HMAC should cover IV + ciphertext
var ivAndCiphertext = buffer.Slice(keyModifierLength, ivLength + ciphertextLength);

// But the buggy code computed something like:
var wrongSlice = buffer.Slice(wrongOffset, wrongLength);
HMACSHA256.HashData(validationSubkey, wrongSlice, wrongDestination);
// The tag landed in the wrong place or was overwritten

Why it matters: CWE-347 in practice

CVE-2026-40372 is classified as CWE-347: Improper Verification of Cryptographic Signature. The CVSS 3.1 vector tells the story:

AV:N / AC:L / PR:N / UI:N / S:U / C:H / I:H / A:N

In concrete terms: if you use cookie authentication (which is the default for ASP.NET Core Identity, Blazor Server, and many SPA setups), an attacker who understands the payload format can construct a forged authentication cookie with arbitrary claims — an admin role, a different user ID, whatever they like. The HMAC validation that should reject the forgery was not functioning.

Anti-forgery tokens, TempData protected via Data Protection, and any custom uses of IDataProtector were equally affected.

Who is affected

The vulnerability scope depends on which encryptor your application uses:

Affected by default:

Affected by configuration:

Not affected:

// IMPORTANT

If you deploy to Linux containers — which includes most Docker-based, Kubernetes, and cloud-native setups — you are in the "affected by default" category. This is not a niche configuration.

How to fix it

Update to .NET 10.0.7. The fix corrects the byte range used for HMAC computation in both the encrypt and decrypt paths of ManagedAuthenticatedEncryptor.

If you use the .NET SDK:

global.json
dotnet --list-sdks
# Verify 10.0.xxx is installed, then update
dotnet workload update

If you reference the package directly:

Directory.Packages.props
<PackageVersion Include="Microsoft.AspNetCore.DataProtection" Version="10.0.7" />

For self-contained deployments, you need to rebuild against the updated runtime. Framework-dependent deployments pick up the fix automatically once the host has the 10.0.7 runtime installed.

Verify the installed version:

terminal
dotnet --info | grep "Microsoft.AspNetCore.App 10.0"

You should see 10.0.7 or later. If you still see 10.0.6 or earlier, the update has not been applied.

// TIP

If you manage deployments across multiple environments, use a health check endpoint that reports the runtime version. This makes it straightforward to verify the patch has been rolled out everywhere.

The decryption regression angle

There is a secondary concern. If your application protected data under .NET 10.0.5 or earlier (using the buggy HMAC), that data has an incorrect HMAC tag baked into it. After updating to 10.0.7, the now-correct HMAC validation will reject those old payloads.

For authentication cookies, this is a non-issue — users simply get logged out and re-authenticate. The cookies are short-lived by design.

For long-lived protected data (encrypted configuration values, tokens stored in a database, etc.), you may need to re-protect those values after updating. The Data Protection system's key rotation handles this transparently for most use cases, but if you have stored protected payloads outside the normal key management flow, audit them.

// WARNING

Do not disable HMAC validation or downgrade to work around the decryption regression. The regression is the correct behaviour — it means validation is finally working. Downgrading re-exposes the vulnerability.

Common pitfalls

"We're on Windows, so we're fine." Probably, but check. If anyone on your team configured UseCustomCryptographicAlgorithms with ManagedAuthenticatedEncryptorConfiguration — perhaps for FIPS compliance or cross-platform key portability — you are using the managed path regardless of the OS.

"We don't use cookies, we use JWT bearer tokens." Data Protection is not just for cookies. Anti-forgery tokens, TempData, and any explicit IDataProtector usage go through the same pipeline. If your API has a Razor-based admin panel, a Blazor component, or uses [ValidateAntiForgeryToken] anywhere, you are exposed.

"We'll update next sprint." This is a CVSS 9.1 with network access, no privileges, and no user interaction. The exploit is straightforward once an attacker understands the payload format, which is publicly documented. Treat this as a same-day patch.

"We're on .NET 8 LTS, this doesn't affect us." Correct. The managed encryptor bug was introduced in .NET 10.0.0. If you are on .NET 8 or .NET 9, you are not affected by this specific CVE. But do still apply the regular April 2026 servicing updates for the other vulnerabilities.

Summary