If a malicious NuGet package reached your build, find every project that restored it, stop restores from resolving it, rotate secrets those builds could read, and rebuild from known good versions. Afterward, use package source mapping and central package management so a package cannot arrive from the wrong feed unnoticed.
How could a bad package get in?
NuGet's documentation explains the root of one common route. By default NuGet searches all configured package sources when it needs a package. When a package ID exists on several sources, it may not be deterministic which one the download comes from. If you mix a private feed with the public one, an attacker can publish a public package with the same ID as an internal one.
Other routes are typosquats, a hijacked maintainer account, and a new version of a trusted package. Your response is the same for all of them.
What do you do in the first hour?
- Identify the package ID and versions. Write them down exactly.
- Search for use. In each repository, run
dotnet list package --include-transitiveand search for the ID. Check lock files and build outputs too. A software bill of materials per release makes this a query rather than a hunt. - Contain. Block the ID in your internal feed or proxy, and pause pipelines that restore it.
- Treat builds as exposed. A NuGet package can run code at restore or build time through build assets, so any CI agent or developer machine that restored it should be considered compromised. Rotate secrets that were available there.
- Clear caches. Delete the package from the global packages folder with
dotnet nuget locals global-packages -c, and from any shared agent cache. - Rebuild from clean agents with the package removed or pinned to a known good version.
- Check deployed artifacts for the package and redeploy where needed.
How does package source mapping help?
Package Source Mapping was added in NuGet 6.0. It lets you decide, per package, which sources NuGet searches. You declare mappings in nuget.config under a packageSourceMapping element. In Microsoft's example, Contoso.* and NuGet.Common come from the private feed and everything else from nuget.org.
Rules worth knowing:
- Once you define the element, every package, including transitive ones, must match a pattern.
- The most specific pattern wins, and the generic
*has the lowest precedence. - Mapping applies during restore, install and update. It does not filter metadata queries from commands such as
dotnet list package --vulnerable, which send package IDs to all configured sources. - If a package already sits in the global packages folder, no source lookup happens and the mapping is ignored. Microsoft suggests a repository specific global packages folder to get the full benefit.
- Older tooling ignores the configuration, so make sure all build environments are on compatible versions: .NET SDK 6.0.100 or later, nuget.exe 6.0.0 or later.
Microsoft also describes a tool, NuGet.PackageSourceMapper, that generates a mapping from a successful restore.
What does central package management add?
Central Package Management puts versions in one Directory.Packages.props file at the repository root, with ManagePackageVersionsCentrally set to true. Project files then list packages without versions. That means a version bump is one reviewable line in one file.
Two settings matter for security. Transitive pinning, enabled with CentralPackageTransitivePinningEnabled, lets you force a safe version of a transitive dependency. Downgrades are not allowed through it. And Microsoft notes NuGet logs an NU1507 warning if several package sources are configured while using central management, which is a nudge to add source mappings.
What to do
- Keep a per release SBOM so you can answer where a package is used.
- Add
nuget.configwith aclearelement, explicit sources and source mappings. - Use central package management and review changes to
Directory.Packages.props. - Use a repository specific global packages folder.
- Write the first hour checklist above into your incident runbook.
- Rotate build secrets as part of any package incident.
Safeguard's dependency scanning and the free scan at gold.safeguard.sh/scan can help with step 1. See the dependency inventory demo.
Quick check
Does source mapping stop a package already in the global packages folder?
No. Microsoft says that when the package is already in the global packages folder, no source lookup happens and the mappings are ignored.
Which NuGet version added Package Source Mapping?
NuGet 6.0.
Sources
Last reviewed: 18 October 2026.