.NET 11 Preview 5 turns end-of-life and known-CVE status into a build warning. That's an important shift that draws a line between the codebases that participate in modern lifecycle hygiene and the ones that structurally can't.
In .NET 11 Preview 5, Microsoft added something that looks minor in the release notes and is actually a statement of direction: the SDK can now warn you, at build time, when the .NET SDK you're building with is vulnerable or past end of life.
You opt in with a single property in your project file or Directory.Build.props:
<PropertyGroup> <CheckSdkVulnerabilities>true</CheckSdkVulnerabilities> </PropertyGroup>
Once enabled, the build emits one of two diagnostics. NETSDK1236 fires when your resolved SDK carries known CVEs and points you at the patched version. NETSDK1237 fires when the SDK is end of life and tells you that it will receive no further security updates. The mechanics are deliberately undramatic: on restore, the SDK refreshes release metadata in the background and caches it under your .dotnet directory; the build task reads that cache and never touches the network itself. No cache, no warning. It fails open. You can suppress either code independently with NoWarn.
That's the whole feature. It's worth understanding why it matters, and then why it matters more to the apps that will never see it.
This isn't a new idea so much as a new surface for an old one. NuGet has warned about vulnerable packages for years. The NU1901–NU1904 family turns a known-bad dependency into a build warning you can escalate to an error. Preview 5 extends the same supply-chain logic up one level, from the packages you pull in to the SDK and runtime you build on.
The significance is where the check lives. Vulnerability management has historically been a separate motion: a scanner runs in CI, or a security team files a ticket, or an SBOM gets reviewed quarterly. Putting the check in the build collapses that distance. The moment your platform falls out of support, the compiler tells you, in the same window where you'd see an unused variable. Risk that used to surface in an audit now surfaces in the inner loop.
For teams on current .NET, this is straightforwardly good. EOL is no longer something you have to remember to check; it's something the toolchain volunteers. The cost of staying current drops, because the cost of discovering you've fallen behind drops to roughly zero.
Here's the part the release notes don't say, because they don't have to.
NETSDK1237 is an MSBuild diagnostic. It requires a project, a restore graph, a resolved SDK version, and a build task with the metadata to evaluate against. Every one of those is a modern-.NET construct. The warning is the modern ecosystem's immune system and an immune system only protects the body it's part of.
A VB6 application has no managed SDK. There is no restore, no Directory.Build.props, no resolved framework version for a task to inspect. It cannot emit NETSDK1237 because there is no build step in which the check could fire. The same is true, in spirit, for PowerBuilder, classic ASP, Access, Delphi, and the rest of the pre-.NET estate. These systems don't get a lifecycle warning because they don't participate in the lifecycle model that produces one.
This is the inversion worth sitting with: the tooling that surfaces platform risk is only available to the platforms that aren't the highest risk. The codebases most exposed to an unpatchable vulnerability are precisely the ones the new check cannot see.
The cleanest illustration isn't VB6. It's .NET Framework 4.8, because it looks safe in a way that masks the actual exposure.
Framework 4.8 doesn't follow the modern SDK lifecycle at all. It's a Windows component, serviced through the OS, "supported" for as long as the operating system is. So it will never trip NETSDK1237. By the only signal a casual reader checks, it's fine. But "supported" here means will receive security fixes, not is receiving platform investment. Framework is frozen. No new runtime performance, no new language-runtime features, no new BCL surface, and none of the AI-native and cloud-native primitives that every subsequent .NET release is built around. It is alive enough to never warn you and dead enough to never move you forward.
So the risk profile splits cleanly into three tiers, and the tooling can only see one of them:
Each new .NET release makes the top tier more self-aware about its own decay. The bottom tiers just get quieter.
There's a strategic point buried in the engineering one. Microsoft is steadily instrumenting the cost of being behind and pushing that cost earlier in the development loop: build warnings for EOL SDKs, NuGet warnings for vulnerable packages, analyzers that flag synchronous calls and deprecated APIs. The modern platform is increasingly designed to make stagnation loud.
That design philosophy has a corollary the platform won't state but every modernization team understands: there is no version of this instrumentation that ever reaches a frozen estate. You don't get partial credit for being close. An app is either inside the system that warns, updates, and compounds forward or it's outside, accumulating exposure that no scanner will ever annotate because there's nothing for the scanner to attach to.
This is what we mean when we talk about a Legacy Debt Compounding Curve. It isn't a metaphor about technical aesthetics. It's the literal, observable fact that every release widens the distance between the apps that participate in modern lifecycle management and the apps that can't and Preview 5 just added one more instrument that only the modern side can read.
The build warning is a gate. To get a warning telling you you're current, you first have to be the kind of application a modern SDK can build. For a legacy estate, that's not a configuration change or a dependency bump. It's modernization to current .NET, where the application comes out the other side as a real, buildable, restorable project that the entire modern toolchain can finally see and protect.
That's the work we do. VELO modernizes legacy applications, VB6, PowerBuilder, and others into current, fully-built .NET as a fixed-price outcome, not a multi-year rewrite. The deliverable is an application that compiles, restores, and, yes, gets the build warning the day its SDK falls out of support.
Want to know how much of your legacy apps VELO can modernize? Our Assessment shows you the exact percentage before you commit to anything.