July 17th, 2024

NuGetAudit 2.0: Elevating Security and Trust in Package Management

Introduction

In November 2023 (NuGet 6.8, Visual Studio 17.8, .NET SDK 8.0.100), we released NuGet Audit. NuGet Audit provides warnings during restore when a package with a known vulnerability is used by a project. More information about NuGet Audit, including detailed configuration options can be found on our learn website. New features are still being added, so if you haven’t read the docs recently, consider having another look, or check our release notes, to see if new features that may help you have been added.

Here is a quick summary of available settings that will be available in NuGet 6.12, Visual Studio 17.12, .NET SDK 9.0.100.

Setting Description
NuGetAudit (property) Enable or disable NuGetAudit
NuGetAuditMode (property) Report only direct packages with known vulnerabilities, or report both directory and transitive packages with known vulnerabilities.
NuGetAuditLevel (property) Selects the minimum vulnerability severity level to report on.
NuGetAuditSuppress (item) Don’t warn about specific advisory URLs.
WarningsNotAsErrors (property) This is not NuGet Audit specific, but if your project uses TreatWarningsAsErrors, consider adding NU1901, NU1902, NU1903, and NU1904 to this list to avoid newly disclosed package vulnerabilities from causing restore and build failures.
auditSources (nuget.config) If no audit sources are provided, NuGet will use package sources to download the vulnerability database to use for auditing. NuGet.config’s auditSources will allow you to use nuget.org (or another source’s) vulnerability database, without it being a package source.

A significant change in NuGet Audit in .NET 9 and VS 17.12 is that the NuGetAuditMode default has changed from “direct” to “all”. Projects using TreatWarningsAsErrors may see new errors. You can use WarningsNotAsErrors to keep treating NuGet Audit’s warnings as warnings. Using a Directory.Build.props file can be used to automatically set it in all projects contained within all subdirectories.

What it looks like

On command line restores, NuGet Audit’s warnings will appear like any other MSBuild warning or error:

D:\src\test\vulnTest\ClassLib1\ClassLib1.csproj : warning NU1903: Package ‘Newtonsoft.Json’ 9.0.1 has a known high severity vulnerability, https://github.com/advisories/GHSA-5crp-9r3c-p9vr [D:\src\test\vulnTest\vulnTest.sln]

In Visual Studio, these warnings will appear in the Error List window

VS error list window showing a NuGet Audit warning NU1903

Solution Explorer will show a yellow bar warning you at least one project has a package with a known vulnerability. There is a clickable link to take you to NuGet’s Package Manager UI (PM UI) for the solution. Note: Currently PM UI at the solution level does not show transitive packages, only direct packages.

Additionally, projects using the newer SDK style projects will have a Dependencies node under the project, and any warnings related to a specific package displayed under the package itself. Projects using the older non-SDK style format will have a references node, rather than dependencies, and will not show additional information about package specific warnings or have overlay icons.

Visual Studio's Solution Explorer showing warnings about vulnerable packages

Recommended way to resolve warnings

Getting a warning about packages with known vulnerabilities is only part of the process. Once discovered, action needs to be taken to remove the potential vulnerability from your solution.

The easiest case is when a package you reference directly has the known vulnerability, in which case you update the version to another version that fixes the vulnerability. If no newer version exists, you can try to contact the package owner, but you may need to look for an alternative package and stop using the one with a known vulnerability. See our documentation on auditing package dependencies for more tips on remediation

However, often a vulnerability will be in a transitive dependency, and the solution is not so obvious. Our recommendation is to prefer updates to packages “closest” to your direct references. Though, there’s nothing wrong with just upgrading the package with known vulnerability either.

For example, say your project references package A. Package A has a dependency on package B, which in turn has a dependency on package C. In this example, we’ll consider that package C version 1.0.0 has a known vulnerability, fixed in version 2.0.0. Our recommendation is to first try upgrading package A. If that doesn’t resolve the audit warning, then try upgrading package B. If that doesn’t resolve the audit warning, then upgrade C directly.

How to upgrade transitive packages

In order to upgrade a transitive package to a higher version, you need to add it as a direct package reference. Our docs have more information about NuGet’s dependency resolution algorithm.

Using Central Package Management with the transitive pinning setting, CPM can automate this for you, with the added benefit that when you upgrade your direct package reference and the transitive package is no longer needed, it automatically disappears from your project’s package graph. However, note that CPM with transitive pinning will still cause packages to become dependencies if you pack your project into your own package to share with others, even if your project doesn’t directly call APIs on that package.

Suppressing specific advisories

Sometimes you might determine after a security review that your software is not at sufficient risk for a particular advisory. For example, several serialization libraries in the past had security advisories where there’s a Denial of Service (DoS) risk when an attacker can craft an input that has deep object nesting leading to a stack overflow. Usually, this can be mitigated by telling the serializer to limit the maximum allowed nesting depth. Therefore, if your software is already mitigating the package’s security risk, you might choose to suppress the specific advisory.

To do so, edit the project file with a text or XML editor, and add a NuGetAuditSuppress element within an ItemGroup.

<Project Sdk="Microsoft.NET.Sdk">
  <!--  other parts of the project left out of this example -->
  <ItemGroup>
    <NuGetAuditSuppress Include="https://github.com/advisories/GHSA-6qmf-mmc7-6c2p" />
  </ItemGroup>
</Project>

You can put these MSBuild items in a Directory.Build.props file if you wish to define it in one place but apply to all projects in subdirectories. However, you may also wish to consider only putting it in specific projects that you have done a security review on, to minimize risk that a different project in the solution takes the same dependency and starts using the library in an insecure way.

However, we strongly encourage you to upgrade packages to versions without known vulnerabilities, rather than suppressing the advisory.

How to find transitive package path

There are several ways to find the package path. Which method you prefer depends on what tools you normally use during your development.

dotnet nuget why

On the command line, dotnet nuget why was added to the .NET SDK 8.0.400 and the .NET 9 preview 6 SDK. Pass it a project file and package id, and it will show you why the package is in your package graph, even through project references.

Image dotnet nuget why

Like the rest of the dotnet CLI, it directly only supports SDK style projects. If you have a Visual Studio project that doesn’t work with the .NET SDK, you can restore your project with Visual Studio or MSBuild. NuGet creates a file named project.assets.json in the project’s obj/ directory (technically, using the MSBuild property MSBuildProjectExtensionsPath). Using an up-to-date version of VS 2022, you can also use msbuild -getProperty:ProjectAssetsFile to find the path to the assets file. Finally, starting from the .NET 9 preview 7 SDK, you will be able to pass dotnet nuget why the assets file as a substitute for the project file. For example, dotnet nuget why path\to\project.assets.json System.Text.RegularExpressions.  

VS solution explorer

SDK style projects also provide the full package graph under the project’s Dependency node. It’s also searchable!

First, expand search options and enable “search external files”.

Image VS Solution Explorer search options

Then you can search the package name, and it will show you all instances under each project’s Dependencies node.

Image VS Solution Explorer search results

Visual Studio NuGet Package Manager UI

When you look at the Installed tab in Visual Studio’s package manager UI, when the project uses PackageReference for package management, it will show both direct and transitive packages. Currently this only happens when you manage packages for a project, not for the solution, although we’re working to improve this.

If you mouse hover of a package in the package list, the tooltip will include the name of one direct package that has caused that transitive package to be included in the project.

Image PM UI transitive tooltip

Looking at the assets file manually

All of the above experiences are based on reading NuGet’s assets file, so if none of them work for you, you can always look at the assets file directly to find the same information. The assets file should not be considered a stable format, so we do not recommend building tools that read the file. We already have upcoming feature plans which need to introduce breaking changes in the json schema, though we will change the version number at the top of the file. But this is not a problem when viewing and searching the file manually.

Generally, the assets file can be found in the obj/project.assets.json under your project’s directory, but if you use the .NET SDK’s artifacts output layout, or otherwise change the default layout, you can also find the location by running the following command on a command prompt:

dotnet msbuild -getProperty:ProjectAssetsFile

If your project is non-SDK style, you may get an error about an import that can’t be found. In this case, open Visual Studio’s Developer Command Prompt, and remove the dotnet from the command line, to use Visual Studio’s MSBuild.exe directly.

Use a text editor to search for the package id that has a known vulnerability, look through potentially multiple search results, and you’ll be able to find which packages list that package as a dependency. Repeat with the other packages until you find the information you’re looking for, perhaps the package your project directly references. Here’s an example showing that Newtonsoft.Json, and a few other packages, are dependencies of the package NuGet.Packaging:

      "NuGet.Packaging/5.11.3": {
        "type": "package",
        "dependencies": {
          "Newtonsoft.Json": "9.0.1",
          "NuGet.Configuration": "5.11.3",
          "NuGet.Versioning": "5.11.3",
          "System.Security.Cryptography.Cng": "5.0.0",
          "System.Security.Cryptography.Pkcs": "5.0.0"
        },

Notes on specific packages

System.Net.Http and System.Text.RegularExpressions

These packages are from .NET Core 1.x, and made redundant since .NET Core 2.0. Since all supported .NET platforms also support .NET Standard 2.0, we do not recommend using versions of .NET Standard below 2.0. If your project directly references either of these packages (or any other System.* package version 4.*), you can remove the package reference, as the assembly is built into the target framework’s reference assemblies. If your project is getting these packages transitively, follow our previous guidance in preferring to upgrade packages closer to your project. Hopefully there’s a newer version of the package that no longer uses .NET Standard 1.x or these packages.

Runtime packages

If you look at some of the .NET platform’s security advisories, for example GHSA-hhc7-x9w4-cw47, or GHSA-7fcr-8qw6-92fr, you can see the packages affected all start with Microsoft.NetCore.App.Runtime.* or Microsoft.AspNetCore.App.Runtime.*. These packages are not referenced directly by your project but are instead implicitly added by the .NET SDK itself. In order to stop using vulnerable versions of these packages you must upgrade to a newer version of the .NET SDK.

Upcoming improvements

Work on improving the experience detecting and managing packages with known vulnerabilities hasn’t stopped. Here are some upcoming features we’re working on. You can search our GitHub issues for issues labeled with NuGetAudit to see existing ideas and bug reports. If you have an idea and can’t find an existing issue to upvote, you can create a new feature request there.

PM UI improvements

Currently Visual Studio’s NuGet Package Manager UI only shows transitive packages that are dependencies of packages that the project references directly. But it does not show packages that only come in via project references. This will be changed.

Additionally, when you mouse hover over a transitive package, it shows which direct package reference has caused the transitive package to be included in the project. If a transitive package is brought in by multiple top level packages, only one of the top level packages will be reported. We’re going to improve this so that more information is available, since non-SDK style projects don’t have the Solution Explorer view that SDK style project have.

Supplied By Platform

NuGet and the .NET SDK team are working on a feature named Supplied By Platform, which will allow the .NET SDK to inform NuGet which packages are now part of the .NET reference assemblies. This will allow NuGet to automatically cull those packages from the restore graph. This means that not only will packages like System.Net.Http and System.Text.RegularExpressions automatically be removed and prevent NuGet Audit warnings, but restore performance will improve because any package that lists NETStandard.Library as a dependency (typically version 1.6.1), will have tens of packages removed from the graph, meaning fewer packages to download and recursively check for their own dependencies.

dotnet nuget audit fix

We also want to provide a way to automatically resolve all your project’s known vulnerabilities by running a single command. It will implement the recommended approach described above, analyzing the package graph and testing upgrades find which combination of upgrades removes all packages with known vulnerabilities. Like any automated tool, it won’t be perfect for all scenarios. For example, if a package with a known vulnerability only has fixes in package versions with breaking changes, the fix to resolve known vulnerabilities may leave your project failing to build. But we believe that it will be a good and quick solution for most developers.

Warnings and errors disappearing from Visual Studio’s Error List

We’re aware of an issue where non-SDK style projects (Visual Studio’s new project wizard calls them “.NET Framework” projects) will have NuGet warnings disappear from the error list after one or two builds. We’re investigating what is clearing the error list, and what NuGet needs to do to retain its warnings. A command line restore (msbuild -t:restore) will always display warnings until this is resolved.

Summary

We covered upcoming changes to NuGet Audit, detailing how to identify and resolve vulnerabilities in your NuGet packages. You learned how to set severity levels, suppress specific advisories, and use new tools to manage vulnerabilities and maintain security. Stay tuned for future enhancements to simplify vulnerability management and be sure to view the docs for up-to-date information.

Author

Jon Douglas
Principal Program Manager

Jon Douglas is a Principal Program Manager for NuGet at Microsoft. In his spare time he is most likely spending time with his family, performing comedy improv, or playing video games.

11 comments

Discussion is closed. Login to edit/delete existing comments.

  • Ryan Buening

    What are the valid property/option values for NuGetAuditSeverity? I did not see where that is specified. Can you point to the docs?

  • Alberto Monteiro

    I enabled that in my project and I found a vulnerability that comes from a package that is a source generator, that is a developmentDependency, the nuget audit should warn about the transitive dependencies from this package?

    Is there some way to ignore this package?

    • Andy ZivkovicMicrosoft employee Author

      Hi Alberto,

      Your first sentence ends with a question mark, but I'm not sure what the question is. If you're asking if source generators can have known vulnerabilities, then yes, I can imagine that a source generator could generate insecure code. NuGet itself doesn't try to analyze packages to make decisions if a package with a reported vulnerability is valid or not. If the source that gives NuGet a vulnerabilities list says package X has...

      Read more
  • Salam ELIAS

    Hi, I have VS 2022 17.10.4 and Nuget Package Manager 6.10.1, I also have nuget.exe in my path version "NuGet Command Line 6.10.0.97", of course .Net SDK is 8.0.303 [C:\Program Files\dotnet\sdk]

    When I run dotnet nuget why I get always
    error: Unrecognized command or argument 'why'
    NuGet Command Line 6.10.0.97

    Inside VS, I dont see the tree for vulnerable package but I can see vulnerable packages listed in Nuget Manager.
    Thanks for your help

    Read more
    • Andy ZivkovicMicrosoft employee Author

      Hi Salam, sorry I wasn't clear in the original blog.

      is a new feature that will be available in the .NET8.0.400 SDK, which isn't yet available. If you install preview versions of the .NET 9 SDK, the latest preview already has it built in. Otherwise, the .NET 8.0.400 SDK isn't too far away. I don't think the exact release date is announced publicly, but if you look at the 7.0.400 and 6.0.400 release dates,...

      Read more
      • Salam ELIAS

        Thanks, what is meant by SDK style? Can you please explain what is Style Project?

      • Andy ZivkovicMicrosoft employee Author

        If you create a new Console App project that targets .NET 8, and another project using the "Console App (.NET Framework)" template in Visual Studio, then you compare the contents of the csproj files in a text editor, the differences will become very clear. Seeing the XML for yourself is the easiest way to understand. Here's a pull request, where I migrated all of NuGet's non-SDK style projects to SDK style, allowing us to...

        Read more
  • Petar · Edited

    I'd like to get clarity on including System package versions (some 4.*, some 8.) when CPM and transitive pinning is enabled. My team is still trying to migrate from some old third-party packages that use 4. System packages. My understanding from the article is that referencing System.* package versions should be avoided, or will no longer be required in .NET 9. Please correct me if I'm wrong.

    Here are my questions (assume CPM and transitive pinning...

    Read more
    • Andy ZivkovicMicrosoft employee Author · Edited

      Hi Petar, thanks for the question.

      When in doubt, try creating a new console app (), and try to use the API. If the API is available, then try to remove the package from your solution.

      However, this doesn't work if the package is already a transitive dependency of a package that you use. In which case you will need to upgrade it (either "directly" or with CPM + transitive pinning). Using the tools mentioned above...

      Read more
      • 8171 passgov

        NuGetAudit 2.0 represents a significant step forward in ensuring security and trust within the package management ecosystem. By enhancing the auditing capabilities and integrating more robust security features, this update addresses some of the key vulnerabilities that developers face. It's a crucial advancement for maintaining the integrity of software dependencies, ultimately contributing to safer and more reliable applications. This focus on security will likely foster greater confidence in using NuGet packages, encouraging developers to adopt...

        Read more