This is a master key cut wrong at the factory, but only for a very specific batch of locks
The bug sits in Microsoft.AspNetCore.DataProtection and breaks authenticity checks on protected payloads such as authentication cookies, antiforgery tokens, TempData, and OIDC state. Authoritative Microsoft guidance says the affected package range is 10.0.0 through 10.0.6, with the highest-risk path being apps that actually load the vulnerable NuGet binary at runtime; Microsoft further narrows that primary population to net10.0 apps on Linux, macOS, or other non-Windows OSes, plus a smaller unusual set of net462 / netstandard2.0 consumers.
Microsoft's 9.1 vendor score is fair for the technical impact on a truly affected internet-facing app: pre-auth cookie forgery and decryption of protected payloads are ugly. But it overstates enterprise-wide urgency because the reachable population is sharply constrained by version, package-loading behavior, target framework, and operating system; most ASP.NET Core estates on Windows, 8.x/9.x branches, or safe shared-framework loading paths are out of scope.
4 steps from start to impact.
Find a reachable DataProtection consumer
Shodan, Censys, response-header fingerprinting, or app-specific crawling, but those tools only find the app, not whether the vulnerable 10.0.0-10.0.6 NuGet binary is actually loaded.- Unauthenticated network reachability to the application
- The application actually uses ASP.NET Core DataProtection for privilege-bearing or plaintext-bearing payloads
- The vulnerable package is truly loaded at runtime
- Internet scans cannot reliably prove the vulnerable package-loading condition from banners alone
- Many ASP.NET Core deployments will be safe because they use Windows, 8.x/9.x branches, or a non-vulnerable shared-framework load path
- Some apps expose no useful protected-payload endpoint to unauthenticated users
Build an oracle and forge a payload
MS10-070, and its guidance notes the attack can require many requests per byte recovered. In practice, an operator would use a custom padding-oracle style script or Burp Intruder-style automation to iterate malformed protected payloads until the app leaks enough signal to recover plaintext or craft a forged payload that passes validation.- A target endpoint must process attacker-supplied protected data
- The application must emit distinguishable success/failure behavior during validation
- The target must be on an affected code path
- High request volume is operationally noisy
- Rate limiting, WAFs, reverse proxies, and CDN edge protections can slow or break the oracle
- Applications that homogenize errors or aggressively expire state reduce exploit stability
Replay a forged cookie or state token
curl, Burp Repeater, or a browser session to impersonate a privileged user or tamper with trust-bound workflow state. The impact is strongest where the protected blob directly maps to authorization context or unlocks sensitive application flows.- The protected payload must carry identity, role, or capability data
- The application must trust the DataProtection output for authentication or authorization decisions
- Some applications offload most authorization to an external IdP and keep little privilege state locally
- Least-privilege app design can limit the value of a forged session
- Short session lifetimes can shrink the usable window
Turn temporary access into durable access
10.0.7 unless you rotate the key ring and application-layer artifacts.- The compromised session can trigger issuance of long-lived tokens or secrets
- Those artifacts are stored outside the DataProtection envelope or remain valid after patching
- Not every app issues persistent capability tokens
- Some orgs use short TTLs or secondary approval workflows
- Back-end token issuance may be separately audited
The supporting signals.
| In-the-wild status | No authoritative evidence of active exploitation found in the checked source set, and the CVE is not listed in the CISA KEV catalog. |
|---|---|
| Proof-of-concept availability | No authoritative public exploit repository from Microsoft or dotnet/* was found in the checked source set. Exploit development is still credible because Microsoft compares the bug's capability to MS10-070 and describes oracle-style log artifacts. |
| EPSS | 0.00023 from the user-provided intel block, which is extremely low and consistent with limited near-term mass exploitation pressure; percentile was not confirmed from an authoritative source in the checked set. |
| KEV status | Not KEV-listed; no CISA date-added or due-date metadata exists for this CVE because it is absent from KEV. |
| CVSS vector, interpreted | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N scores it as clean pre-auth network exploitation with high confidentiality and integrity impact. That is technically fair inside the affected slice, but it ignores the package/runtime/OS gating that cuts the reachable population down. |
| Affected versions | Microsoft says Microsoft.AspNetCore.DataProtection 10.0.0 through 10.0.6 are affected. The primary affected configuration is the vulnerable NuGet binary loaded at runtime, especially net10.0 on Linux/macOS/non-Windows; Microsoft also calls out a smaller unusual net462 / netstandard2.0 population. |
| Fixed versions | Vendor fix is 10.0.7. Ubuntu backports show dotnet10 fixed as 10.0.107-10.0.7-0ubuntu1~26.04.1, ~25.10.1, and ~24.04.1 on supported releases. |
| Exposure and scanning reality | This is hard to enumerate from the internet. *Inference from Microsoft's loading rules:* Shodan/Censys-style scanning can find ASP.NET Core exposure, but they cannot reliably tell whether a host loads the vulnerable NuGet asset versus a safe shared-framework copy, so asset inventory and SCA beat perimeter scanning here. |
| Disclosure timeline | Disclosed 2026-04-21; NVD shows publication on 2026-04-21 and later CPE enrichment on 2026-04-27. |
| Reporting / discovery context | Microsoft's .NET blog says the investigation started after customers reported decryption failures following .NET 10.0.6, which led to the security finding and the out-of-band 10.0.7 release. |
noisgate verdict.
The decisive downgrading factor is population narrowing: this is not every ASP.NET Core app, but a specific package/version/runtime-loading problem with major OS and framework exceptions. Still, for the subset that is truly affected and internet-facing, exploitation is pre-auth and can mint durable privileged artifacts, so this stays firmly in HIGH rather than sliding into routine backlog work.
Why this verdict
- Downward pressure: requires a narrow deployment shape — the vulnerable condition is not generic "ASP.NET Core exposed to the internet"; it requires
Microsoft.AspNetCore.DataProtection10.0.0-10.0.6to be the code path actually loaded at runtime. - Downward pressure: big platform carve-outs — Microsoft says Windows
net10.0apps are not affected in the main path, and8.x/9.xpackage lines are not affected, which meaningfully shrinks enterprise exposure. - Downward pressure: internet scanners cannot confirm it well — exposure is to the app endpoint, but vulnerable population depends on internal package-loading behavior, so the mass-exploitable population is smaller than the CVSS suggests.
- Upward pressure: pre-auth remote abuse — there is no attacker authentication requirement if the app exposes a useful protected-payload endpoint.
- Upward pressure: identity compromise, not just info leak — successful exploitation can forge auth cookies and tamper with trust-bound state, which is operationally closer to auth bypass than to a niche crypto bug.
- Upward pressure: cleanup can outlive patching — Microsoft warns that legitimately signed refresh tokens, API keys, or reset links issued during the vulnerable window may survive the
10.0.7upgrade unless keys and app-layer artifacts are rotated.
Why not higher?
This does not earn CRITICAL in patch-priority terms because the real affected population is gated by version, package-reference behavior, runtime loading, framework target, and OS. There is also no KEV listing, no authoritative active-exploitation evidence in the checked source set, and EPSS is extremely low, so this is not a broad internet fire like a generic edge-device RCE.
Why not lower?
This should not drop to MEDIUM because the exploitation path is still pre-auth network reachable on affected internet-facing apps and directly targets authentication trust. If you are in the affected slice, the blast radius is serious: forged privileged sessions, plaintext recovery from protected blobs, and potentially durable secondary tokens.
What to do — in priority order.
- Inventory vulnerable package loads — Use SBOM/SCA,
deps.json, container image inspection, and file-level checks to identify applications that actually loadMicrosoft.AspNetCore.DataProtection10.0.0-10.0.6; do this first because internet recon cannot distinguish safe from unsafe load paths. For a HIGH verdict, complete this identification and triage within 30 days. - Restrict exposure on confirmed-affected apps — For any confirmed affected internet-facing application, reduce reachability with reverse-proxy ACLs, VPN requirements, maintenance windows, or temporary route withdrawal until patched. This is your best risk reducer before full remediation and should be deployed within 30 days.
- Patch to 10.0.7 or distro backport — Move application dependencies or runtime packages to
10.0.7or the vendor backport that contains the fix, then rebuild and redeploy all affected instances. For HIGH, treat this as the actual remediation and finish within 180 days, with internet-facing systems first. - Rotate the DataProtection key ring — Microsoft explicitly warns that patching alone does not invalidate durable artifacts created during the vulnerable window. After upgrading affected internet-exposed apps, rotate the key ring within 30 days so forged or transitively issued trust artifacts stop working.
- Rotate application-issued durable tokens — Invalidate refresh tokens, API keys, password-reset links, email-confirmation tokens, and similar capability artifacts issued during the vulnerable period if they could have been minted from a forged session. This is the part most teams miss, and it should be done within 30 days for confirmed-affected internet-facing apps.
- Watch for oracle-style abuse — Review web and reverse-proxy logs for sustained high-volume requests with changing cookie or query-parameter values against endpoints that accept protected payloads. Stand up this detection within 30 days to catch exploitation attempts and to scope whether cleanup needs to widen.
- MFA at the login page does not stop forged post-auth session cookies; the attacker is abusing the application's trust in protected payloads, not stealing a password interactively.
- A generic WAF signature is not enough; this is application-specific oracle traffic and may look like repeated malformed cookie or state values rather than a clean exploit string.
- Patching without key rotation is incomplete; Microsoft says legitimately signed downstream artifacts issued during the vulnerable window can remain valid after upgrade.
- Perimeter scanning alone is misleading; it can show you exposed ASP.NET Core apps, but not whether the vulnerable NuGet code path is what the process actually loads.
Crowdsourced verification payload.
Run this on the target Linux or macOS host that contains the deployed app files, not from an auditor workstation. Invoke it as ./check-cve-2026-40372.sh /srv/myapp with read access to the app directory and optional access to dotnet --list-runtimes; no root is required unless the deployment path is restricted.
#!/usr/bin/env bash
# check-cve-2026-40372.sh
# Detect likely exposure to CVE-2026-40372 in deployed ASP.NET Core apps.
# Usage: ./check-cve-2026-40372.sh /path/to/app
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN, 3=usage/runtime error
set -u
APP_DIR="${1:-}"
if [[ -z "$APP_DIR" || ! -d "$APP_DIR" ]]; then
echo "UNKNOWN - usage: $0 /path/to/app"
exit 3
fi
if ! command -v python3 >/dev/null 2>&1; then
echo "UNKNOWN - python3 is required"
exit 2
fi
OS_NAME="$(uname -s 2>/dev/null || echo unknown)"
case "$OS_NAME" in
Linux) OS_FAMILY="linux" ;;
Darwin) OS_FAMILY="macos" ;;
*) OS_FAMILY="other" ;;
esac
DEPS_FILE="$(find "$APP_DIR" -maxdepth 2 -type f -name '*.deps.json' | head -n 1)"
DLL_FILE="$(find "$APP_DIR" -maxdepth 3 -type f -name 'Microsoft.AspNetCore.DataProtection.dll' | head -n 1)"
MAX_ASPNET_RUNTIME=""
if command -v dotnet >/dev/null 2>&1; then
MAX_ASPNET_RUNTIME="$(dotnet --list-runtimes 2>/dev/null | awk '/^Microsoft\.AspNetCore\.App 10\./ {print $2}' | sort -V | tail -n 1)"
fi
export APP_DIR DEPS_FILE DLL_FILE OS_FAMILY MAX_ASPNET_RUNTIME
python3 <<'PY'
import json, os, re, sys
from pathlib import Path
app_dir = Path(os.environ['APP_DIR'])
deps_file = os.environ.get('DEPS_FILE', '')
dll_file = os.environ.get('DLL_FILE', '')
os_family = os.environ.get('OS_FAMILY', 'other')
max_runtime = os.environ.get('MAX_ASPNET_RUNTIME', '')
def parse_ver(v):
m = re.match(r'^(\d+)\.(\d+)\.(\d+)', v or '')
return tuple(map(int, m.groups())) if m else None
def in_vuln_range(v):
p = parse_ver(v)
return p is not None and (10, 0, 0) <= p <= (10, 0, 6)
def is_patched(v):
p = parse_ver(v)
return p is not None and p >= (10, 0, 7)
pkg_versions = set()
tfms = set()
if deps_file:
try:
data = json.loads(Path(deps_file).read_text(encoding='utf-8', errors='ignore'))
for target_name, target in (data.get('targets') or {}).items():
tfms.add(str(target_name))
for lib_name in (target or {}).keys():
if lib_name.startswith('Microsoft.AspNetCore.DataProtection/'):
pkg_versions.add(lib_name.split('/', 1)[1])
for lib_name in (data.get('libraries') or {}).keys():
if lib_name.startswith('Microsoft.AspNetCore.DataProtection/'):
pkg_versions.add(lib_name.split('/', 1)[1])
except Exception:
print('UNKNOWN - failed to parse deps.json')
sys.exit(2)
# Fast path: deployed vulnerable DLL present locally in app payload.
if dll_file and pkg_versions:
vuln_versions = sorted(v for v in pkg_versions if in_vuln_range(v))
patched_versions = sorted(v for v in pkg_versions if is_patched(v))
if vuln_versions and not patched_versions:
print(f'VULNERABLE - local app payload includes Microsoft.AspNetCore.DataProtection {vuln_versions[-1]} and no patched package detected')
sys.exit(1)
# If patched package present in deps, call it patched.
if any(is_patched(v) for v in pkg_versions):
print('PATCHED - deps.json references Microsoft.AspNetCore.DataProtection 10.0.7 or later')
sys.exit(0)
# No package reference found. We cannot prove vulnerability from a generic host scan.
if not pkg_versions:
if max_runtime and is_patched(max_runtime):
print(f'PATCHED - no vulnerable package reference found and host has Microsoft.AspNetCore.App {max_runtime}')
sys.exit(0)
print('UNKNOWN - no DataProtection package reference found; this check only confirms vulnerable package-loaded deployments')
sys.exit(2)
# Package reference exists; decide based on Microsoft narrowing rules.
vuln_versions = sorted(v for v in pkg_versions if in_vuln_range(v))
if not vuln_versions:
print('PATCHED - DataProtection package present but not in 10.0.0-10.0.6 range')
sys.exit(0)
# net10.0 on Linux/macOS with shared framework >= package version is considered safe by Microsoft when the shared framework copy is loaded.
package_ver = vuln_versions[-1]
uses_net10 = any('net10.0' in t for t in tfms)
uses_legacy_assets = any(('net462' in t or 'netstandard2.0' in t) for t in tfms)
if uses_net10 and os_family in ('linux', 'macos'):
if max_runtime and parse_ver(max_runtime) and parse_ver(max_runtime) >= parse_ver(package_ver) and not dll_file:
print(f'PATCHED - vulnerable package version {package_ver} referenced, but no local DLL found and shared framework {max_runtime} should win at runtime')
sys.exit(0)
if dll_file:
print(f'VULNERABLE - net10.0 {os_family} app appears to deploy/load local DataProtection {package_ver}')
sys.exit(1)
print(f'UNKNOWN - vulnerable package version {package_ver} referenced on net10.0 {os_family}; verify whether the NuGet binary or shared framework is loaded at runtime')
sys.exit(2)
if uses_legacy_assets:
print(f'VULNERABLE - legacy target asset path references Microsoft.AspNetCore.DataProtection {package_ver}, which Microsoft flags as affected')
sys.exit(1)
# Windows-primary path is not the target of this bash check; anything else remains uncertain.
print(f'UNKNOWN - vulnerable package version {package_ver} detected, but runtime-loading conditions could not be proven from filesystem data alone')
sys.exit(2)
PYIf you remember one thing.
9.1 panic and start with precision inventory: find the apps that truly load Microsoft.AspNetCore.DataProtection 10.0.0-10.0.6, especially internet-facing net10.0 workloads on Linux/macOS and any odd net462 / netstandard2.0 consumers. For the HIGH verdict, the noisgate mitigation SLA is within 30 days: restrict exposure on confirmed-affected apps, patch internet-facing instances first, rotate the DataProtection key ring, and invalidate durable tokens issued during the vulnerable window; the noisgate remediation SLA is within 180 days to fully move every affected deployment to 10.0.7 or an equivalent distro backport and close out the fleet.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.