Safeguard
Supply Chain•

NuGet package source mapping: how to onboard a repository

Package source mapping tells NuGet which feed each package ID may come from. Here are the nuget.config syntax, precedence rules and onboarding steps.

Safeguard Security Team
3 min read

NuGet package source mapping lets you say which feed each package ID may be restored from. By default NuGet searches every configured source, so a package that exists on several feeds may come from any of them. A mapping in nuget.config removes that guesswork and blocks the usual dependency confusion path.

What it does

Microsoft's documentation explains that by default NuGet searches all configured package sources, and when a package exists on multiple sources it may not be deterministic where it comes from. With mapping you filter, per package, which sources NuGet will search. The feature arrived in NuGet 6.0 and works with .NET SDK 6.0.100 and later and nuget.exe 6.0.0 and later. Older tooling ignores the configuration, so make sure every build environment is current.

The nuget.config syntax

<configuration>
  <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.*" />
      <package pattern="NuGet.Common" />
    </packageSource>
  </packageSourceMapping>
</configuration>

The clear element stops sources being inherited from other config files. Declare one packageSource element per source.

Precedence

A pattern is either an exact package ID or a prefix ending with a star. When several match, the most specific wins: exact IDs first, the lone star last, and for prefixes the longest one. So Contoso.Core goes to contoso.com even though the star pattern on nuget.org also matches.

Every package needs a match

Once the mapping section exists, every package, transitive ones included, must match a pattern. A top level package and its dependencies do not need to share a source. Mapping the same pattern to several sources is allowed but hurts predictability.

Onboarding steps

The documentation suggests this manual path:

  1. Declare a repo specific global packages folder.
  2. Run dotnet restore.
  3. Run dotnet list package --include-transitive to see every package.
  4. Write mappings so each ID matches a pattern.
  5. Clear the global packages cache with dotnet nuget locals global-packages -c.
  6. Restore again. Errors point to unmapped IDs.

Microsoft also offers a NuGet.PackageSourceMapper tool that generates a config from a successful restore.

Limits to know

If a package is already in the global packages folder, no source lookup happens and the mapping is ignored, hence the dedicated folder in step 1. Mapping applies when NuGet downloads packages. Commands such as dotnet list package and dotnet package add still send package IDs to all configured sources, including public ones.

A sensible default

If you mostly use nuget.org and have a few internal packages with a shared prefix, map the star to nuget.org and the prefix to your private feed. If you do not have standard prefixes, or you vet public packages before use, make the private feed the default.

For the underlying attack, see what a dependency confusion attack is.

Safeguard dependency and SBOM scanning can list the packages in a .NET repository and flag known vulnerabilities. You can try a free scan at gold.safeguard.sh/scan.

Click through it at your own pace, or open it full screen.

Quick check

Which pattern wins when two match?

The most specific. Exact IDs beat prefixes, longer prefixes beat shorter ones, and the lone star is last.

Why did my mapping seem ignored?

The package may already be in the global packages folder, in which case NuGet does no source lookup.

Sources

Last reviewed: 19 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.