NuGet Packages: security risks and best practices

 
 
  • Gérald Barré

NuGet packages offer a convenient way to share code, but many developers download them without reviewing the contents or verifying updates when new versions are released. When you install a NuGet package, you are:

  • Downloading code from unknown authors that has likely not been thoroughly reviewed by others
  • Running it with full permissions on your local machine, potentially exposing your personal data
  • Executing it with full access on continuous integration (CI) machines, putting your secrets and environment at risk

It's surprising that there aren't more incidents! Let's take a closer look at what could go wrong.

#What can a NuGet package do?

##MSBuild props and targets

A NuGet package can contains MSBuild files that are automatically imported when building the project. These files can change the build process of your application. It can run a target that executes commands or run C# code dynamically. It can also change the code of your application before building it.

You can check the content of the files under the build, buildMultitargeting and buildTransitive folders of the NuGet package.

##Roslyn Analyzers and Source Generators

NuGet packages can contains Roslyn analyzers. Roslyn analyzers are executed at design (IDE) and build time and can do anything on your machine. While analyzers are meant to analyze code, they are actually running inside the compiler process and can do anything they want (there is no sandbox). You can write files, update the binaries after compilation, etc.

Roslyn source generators are very similar to analyzers, so the same security concerns apply. They can also add or update code of your application when building it.

Note that you can prevent loading analyzers from a package by using the IncludedAssets or ExcludedAssets properties in the .csproj file. For instance, you can use the following code to only load the libraries from a package:

XML
<PackageReference Include="Meziantou.Framework.InlineSnapshotTesting" Version="3.2.1">
    <IncludeAssets>compile</IncludeAssets>
</PackageReference>

More info about controlling dependency assets

##Libraries

Are you sure the DLL in the NuGet package are the ones you think? Even if the code is on GitHub, are you sure the DLLs are built from this code? You can check the content of the DLL by decompiling it. If the symbols (PDB) are provided and contains the right information, you can automatically validate that the code is built from the provided source code.

##Code execution when installing/uninstalling a package

NuGet packages can contain PowerShell scripts that are executed when the package is installed or uninstalled. Note that these scripts are only executed for projects that don't use <PackageReference>. So, this is not a concern for most modern projects.

Before installing a package be sure to check the content of the package. You can do this by downloading the package and extracting it. Be sure to check the following files:

  • tools/init.ps1
  • tools/install.ps1
  • tools/uninstall.ps1

#Other vector attacks

##Typo squatting

A malicious person can create a package with a similar name to a popular package. For example, Newtonsoft.Json can be replaced by Newtomsoft.Json or Newtomsoft-Json. This is called typo squatting. Be sure to check the package name before installing it.

Note that nuget.org allows to reserve a prefix to prevent this kind of attack. For instance, I'm the only one that can create a package with the meziantou prefix. Also, all my packages have a checkmark to indicate that they are from reserved prefix.

##Same package as a private package

If you have a package published on an internal feed such as Azure Packages, with the same name as a public package, the public package can be used instead of the private one. This is a security issue because you don't know the content of the public package. You can use package source mapping to prevent this issue.

Read more about this in this post: Faster and Safer NuGet restore using Source Mapping and Lock files

##Removed package

Even if you validated a package and install it, you may not be safe. On nuget.org, you cannot remove a package. You can only mark it as unlisted. When a package is unlisted, it is not visible on the website or for package graph resolution. If the package is updated, you will get the new version automatically. This means that your application may use a new version of the package that you didn't validate.

To prevent this issue, you can use a lock file. A lock file is a file that contains the exact version of the packages you use. When you restore the packages, you get the exact version you used before.

Read more about this in this post: Faster and Safer NuGet restore using Source Mapping and Lock files

#Best practices

#Conclusion

If you read the previous points correctly, you understand that a NuGet package can:

  • Execute code on your machine, with the current user permissions
  • Execute code on your CI machines, with the permissions of the CI user
  • Change the code of your application, and potentially add malicious code. So, it can execute code on your production machines.

Most packages are safe, but you don't know what can happen in the future. A compromised NuGet or GitHub account is not something that is rare. So, be sure to check the content of the packages you install or update.

Last but not least, other package managers have similar issues. Be vigilant when using any package!

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

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub