Limit what NuGet packages can do in your project

 
 
  • Gérald Barré

When you add a NuGet package to a project, you often think about the runtime library only. In reality, packages can also import MSBuild props/targets and Roslyn analyzers. Those assets run during restore, design-time build, or build. I've already provided some examples of how this can cause issues in NuGet Packages: security risks and best practices.

This means a package can execute code on your machine or in CI without you notice. If you only need a subset of a package assets, you can restrict what is imported by using IncludeAssets and ExcludeAssets on PackageReference.

#Why this matters

NuGet packages may include:

  • build, buildMultitargeting, and buildTransitive files (MSBuild props and targets)
  • analyzers (including source generators)
  • runtime and compile libraries

If you do not need build logic or analyzers from a package, blocking them reduces your attack surface and makes builds more predictable. If you read the recent news about supply-chain attacks, you know that any code running on your machine or CI is a potential risk. By default, all assets from a package are imported, so it's important to be aware of this and take action when needed.

#Include only what you need

The safest pattern is often to allow only the assets you need.

XML
<ItemGroup>
    <PackageReference Include="Some.Package" Version="1.2.3">
        <IncludeAssets>compile;runtime</IncludeAssets>
    </PackageReference>
</ItemGroup>

With this configuration, NuGet does not import analyzers or build targets from the package.

#Exclude specific asset types

If you prefer to keep default behavior and remove only some asset groups, use ExcludeAssets.

XML
<ItemGroup>
    <PackageReference Include="Some.Package" Version="1.2.3">
        <ExcludeAssets>analyzers;build;buildMultitargeting;buildTransitive</ExcludeAssets>
    </PackageReference>
</ItemGroup>

This is useful when you still want other assets such as contentFiles.

#Common scenarios

##Include only runtime/library assets

XML
<PackageReference Include="Some.Package" Version="1.2.3">
    <IncludeAssets>runtime;compile</IncludeAssets>
</PackageReference>

##Keep the runtime library, disable analyzers

XML
<PackageReference Include="Some.Package" Version="1.2.3">
    <ExcludeAssets>analyzers</ExcludeAssets>
</PackageReference>

##Keep analyzers, disable build targets

XML
<PackageReference Include="Some.Package" Version="1.2.3">
    <ExcludeAssets>build;buildMultitargeting;buildTransitive</ExcludeAssets>
</PackageReference>

##Use a package for build tooling only

XML
<PackageReference Include="Some.Package" Version="1.2.3" PrivateAssets="all">
    <IncludeAssets>build;buildMultitargeting;buildTransitive</IncludeAssets>
</PackageReference>

PrivateAssets="all" prevents the dependency from flowing transitively to projects that reference your project.

#Notes and caveats

  • Some packages require analyzers or build targets to work correctly. Test after changing asset filters.
  • Prefer explicit and documented choices in .csproj files for critical dependencies.
  • Combine this with package lock files and package source mapping for stronger supply-chain protection.

#Additional resources

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?