Safeguard
Software Supply Chain•

How do you defend NuGet builds against typosquatting and confusion?

NuGet tries every configured source by default. Map each package ID to one source, verify signatures and review new names to stop confusion and typosquats.

Safeguard Security Team
4 min read

Two defenses cover most NuGet risk. Package source mapping makes each package ID restore from a named source only, which stops dependency confusion. Careful review of new package names, plus signature checks, covers typosquats. Neither is on by default, so both need explicit configuration in your repository.

Why does NuGet need source mapping at all?

Microsoft's documentation is direct about the default: NuGet searches all configured package sources when it needs to download a package. When a package exists on several sources, it may not be deterministic which one is used.

That is the dependency confusion setup. Suppose your company publishes Contoso.Billing.Core to a private feed. If an outsider registers the same ID on the public feed with a higher version number, a restore that queries both feeds can pick the outsider's package. Nothing in your code changed. Your configuration just left the choice open.

How does package source mapping close the gap?

Source mapping was added in NuGet 6.0. You add a packageSourceMapping section to nuget.config that lists, for each source, the package ID patterns it may serve. Here is the shape, adapted from the Microsoft example:

<packageSources>
  <clear />
  <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
  <add key="contoso.com" value="https://contoso.com/packages/" />
</packageSources>
<packageSourceMapping>
  <packageSource key="nuget.org">
    <package pattern="*" />
  </packageSource>
  <packageSource key="contoso.com">
    <package pattern="Contoso.*" />
  </packageSource>
</packageSourceMapping>

Rules worth knowing: once mapping is on, every package, including transitive ones, must match a pattern. The most specific pattern wins, exact IDs beat prefixes, and the longest prefix beats shorter ones. The bare star is lowest priority, so it works as a default source.

What are the gaps in source mapping?

The documentation lists real limits. Mapping applies when NuGet downloads packages during restore, install and update. Commands that look up metadata, such as listing outdated or vulnerable packages with the dotnet CLI, send package IDs to all configured sources. Older tooling ignores the configuration, so every build environment needs a compatible version: nuget.exe 6.0.0 or later, or the .NET SDK 6.0.100 or later.

One more catch: if a package already sits in the global packages folder, no source lookup happens and the mapping is skipped. Microsoft suggests declaring a repository-specific global packages folder to get the full benefit.

What about typosquats?

A typosquat is a different problem. The package ID is new to you, so no mapping rule says it is wrong, since the star pattern will happily send it to nuget.org. Defense is review:

  • Compare the ID with the project's own documentation, character by character.
  • Look at the publisher, publish date and download history before the first install.
  • Prefer packages with signatures you can verify.

NuGet packages can be signed. An author signature proves the package is unchanged since the author signed it, and the signing certificate must be registered with nuget.org in advance. All packages uploaded to nuget.org are repository signed automatically. You can check a downloaded package with the dotnet nuget verify command. A signature shows consistency with a publisher identity, not that the publisher is benign, so treat it as one input.

What to do

  1. Add a single nuget.config at the repository root, with clear first so no sources are inherited.
  2. List every package, transitive included, using the dotnet list package command with the include-transitive option.
  3. Define mappings so each internal prefix points at the private feed and everything else at one public source.
  4. Use the NuGet.PackageSourceMapper tool if your solution is large. It generates mappings from a completed restore.
  5. Set a repository-level global packages folder and clear the old one, then restore to prove the mapping holds.
  6. Require review for any new package ID in a pull request.
  7. Check that every CI image uses a NuGet version that honors mapping.

Safeguard can scan a dependency inventory for malicious and vulnerable packages as part of a pull request gate, which suits step 6.

Quick check

Does source mapping stop typosquatting?

No. It stops the wrong source from supplying a name you expect. A typosquat is a different name, so you catch it through review of new package IDs.

Why did my mapping seem to be ignored?

If the package was already in the global packages folder, NuGet skips the source lookup. Older NuGet versions also ignore the section, so check the tool version in CI.

Sources

Last reviewed: 18 October 2026.

Never miss an update

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

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.