Open Source Security

.NET / NuGet Enterprise Supply Chain Program

An enterprise-grade .NET and NuGet supply chain program for 2026 — covering feeds, lockfiles, MSBuild targets, and runtime — backed by Safeguard.

Nayan Dey
Senior Security Engineer
7 min read

The .NET ecosystem has spent the last five years quietly catching up to the rest of the world on supply chain security. Lockfiles are now stable. Central package management has shipped. Source link and SourceLink-style provenance is widely adopted. The cross-platform story is mature enough that enterprise teams routinely build and ship on Linux. And yet a surprising number of large .NET shops are still running 2018-vintage supply chain programs: a single internal NuGet feed, no lockfile enforcement, no policy gates, and a runtime inventory that lives in a spreadsheet.

This post is the 2026 enterprise-grade program for .NET and NuGet. It assumes a reader who already knows .NET well and is being asked, often for the first time, to build a defensible supply chain program around it.

The .NET threat surface

NuGet attacks rhyme with attacks on every other public registry — typosquats, dependency confusion, hijacked maintainer accounts, malicious version bumps — but two .NET-specific properties shape the threat model.

The first is MSBuild. Every NuGet package can ship .props and .targets files that MSBuild includes during build, with full ability to run tasks, add references, and modify the build graph. A compromised .targets file is a compromised build, and the surface is invisible to anyone who is only reading the C# in the project. The 2026 program treats MSBuild integration as part of the supply chain on the same footing as runtime DLLs.

The second is the Microsoft trust gradient. .NET teams have historically extended a higher level of trust to packages published from microsoft.com domains, and that trust is mostly justified, but it has occasionally been abused — by typosquats that mimic Microsoft package names, by community packages that adopt Microsoft-style naming conventions, and by genuine Microsoft packages that pull in less-trusted transitive dependencies. The program does not abolish the trust gradient; it makes it explicit and enforceable.

Layer one: the feed

The first control is a private NuGet feed as the only allowed source. Azure Artifacts, ProGet, Artifactory, and GitHub Packages all support the model. The feed proxies nuget.org with a quarantine in front of it, and Safeguard scans every package that arrives.

The scan covers the standard checks — blocklists, typosquat heuristics, license rules, age thresholds — plus two .NET-specific checks. The first is a publisher-signature check: NuGet supports author signing, and a package whose signature does not chain to a known publisher certificate is held for review. The second is an MSBuild integration check: packages that ship .props or .targets files are flagged for explicit review, with the integration content surfaced in the finding so the reviewer can see what the build will execute.

For internally published packages, the program adds repository signing as a hard requirement. Internal feeds sign every package on the way in, and downstream consumers verify the signature before restoring. The signing key lives in Azure Key Vault or an HSM, never in a build agent.

Layer two: lockfiles and central package management

The .NET lockfile story has been confused for years and is finally simple. Central package management with packages.lock.json enabled at the solution level, and RestoreLockedMode set in CI, gives a deterministic restore that fails if any version drifts.

The 2026 baseline is non-negotiable: every solution uses central package management, every project enables lockfiles, every CI build runs with locked mode, and any pull request that touches a Directory.Packages.props or a packages.lock.json is gated by a Safeguard policy evaluation.

The policy gates evaluate the full transitive graph. .NET projects can have surprisingly deep transitive trees because of the many compatibility shims and runtime packages that the framework pulls in, and the gates run against all of them. The gates also enforce a Microsoft-package allowlist: packages from the Microsoft.* and System.* namespaces are allowed by default, but a non-Microsoft package that uses one of those namespace prefixes is treated as a typosquat candidate and held.

Layer three: MSBuild and SDK targets

MSBuild is the .NET build supply chain. The program reviews every .props and .targets file that arrives via NuGet, maintains an explicit allowlist of packages that are permitted to extend the build, and treats unreviewed build extensions as policy violations.

The SDK itself — Microsoft.NET.Sdk and its many specialised siblings — is part of the supply chain too. The 2026 program pins SDK versions in global.json, tracks SDK security releases through an automated channel, and rebuilds CI images on a defined cadence rather than waiting for an emergency.

Source generators and analyzers get the same treatment as proc-macros in the Rust program. They run arbitrary code at compile time with access to the source, and they have the same potential to rewrite code on the way through the compiler. The allowlist for source generators is small, deliberate, and reviewed on every version bump.

Layer four: the build

The .NET build environment follows the same pattern as every other ecosystem in the program: ephemeral runners, restricted egress, single-use credentials, and a signed output. The output for a typical service is a self-contained or framework-dependent publish output, accompanied by a CycloneDX SBOM and a SLSA provenance statement.

The SBOM is generated from the lockfile plus the published output, with reconciliation between the two so that anything in the publish directory that did not come from the lockfile — a stray DLL from a build script, a runtime package that the SDK pulled in implicitly — surfaces as a finding. Safeguard stores the SBOM and provenance together and ties them to the commit and pipeline run.

For applications shipped as containers, the SBOM extends down to the base image. The program treats the .NET runtime image as part of the supply chain, with the same pinning, scanning, and rebuild discipline as the rest of the dependency graph.

Layer five: runtime

The .NET runtime is itself supply chain. The program pins specific runtime versions, tracks Microsoft's security advisory feed, and rebuilds container images on a defined cadence. Self-contained deployments embed the runtime in the application output, which means a runtime CVE is a per-application incident; framework-dependent deployments share the runtime across applications, which means a runtime CVE is a fleet-wide event. The program tracks both modes in the inventory and treats them differently in incident response.

Safeguard's runtime inventory links each running application back to its publish output, its SBOM, and its provenance. When a new CVE drops against System.Text.Json or any other runtime package, the question "are we affected, and where?" is a query against the inventory.

Enterprise-specific concerns

Enterprise .NET environments have two patterns that shape the program more than the language itself.

The first is the long tail of legacy. A large .NET enterprise has applications running on Framework 4.8, on Core 3.1 long after end-of-life, and on every version since. The program does not pretend the tail does not exist. It maintains a pinned, reviewed feed for legacy environments, with stricter policy gates that reflect the reduced patching options, and it surfaces every legacy application as a known elevated-risk asset in the inventory.

The second is the Microsoft licensing layer. .NET shops frequently bundle commercial libraries — Telerik, DevExpress, Syncfusion, ComponentOne — that are licensed and shipped through internal feeds. Safeguard treats commercial packages as first-class citizens in the policy, with license-tracking gates that enforce the procurement contract alongside the security policy.

Closing

A 2026 enterprise .NET program is not exotic. It is the standard supply chain program — feed, lockfile, build hardening, SBOM, inventory — applied with .NET-specific care for MSBuild integration, source generators, and the runtime layer. Safeguard is the control plane that makes the program operable. The work is not new; the discipline of doing it consistently, in an ecosystem that has historically gotten less attention than npm or PyPI, is what separates the programs that hold up under audit from the ones that do not.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.