Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 82 additions & 83 deletions docs/concepts/Auditing-Packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,23 +77,7 @@ Note that the [V2 protocol is deprecated](../nuget-org/overview-nuget-org.md#api
| -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| [NuGet 6.12, .NET 9.0.100 SDK, and Visual Studio 2022 17.12](../release-notes/NuGet-6.12.md) | Restore |
| [NuGet 6.14, .NET 9.0.300 SDK](../release-notes/NuGet-6.14.md) | `dotnet package list --vulnerable` |
| Not yet supported | NuGet AuditSources support in the Visual Studio Package Manager UI |

#### Excluding advisories

You can choose to exclude specific advisories from the audit report by adding a new `NuGetAuditSuppress` MSBuild item for each advisory.
Define a `NuGetAuditSuppress` item with the `Include=` metadata set to the advisory URL you wish to suppress.

```xml
<ItemGroup>
<NuGetAuditSuppress Include="https://github.com/advisories/XXXX" />
</ItemGroup>
```

Similar to the other NuGet audit configuration properties, `NuGetAuditSuppress` items can be defined at the project or repository level.

`NuGetAuditSuppress` is available for PackageReference projects starting from [NuGet 6.11, Visual Studio 17.11, and the .NET 8.0.400 SDK](../release-notes/NuGet-6.11.md).
It is available for packages.config from [Visual Studio 17.12 and NuGet 6.12](../release-notes/NuGet-6.12.md).
| [NuGet 7.0 and Visual Studio 2026](../release-notes/NuGet-7.0.md) | NuGet AuditSources support in the Visual Studio Package Manager UI |

### Warning codes

Expand All @@ -113,90 +97,49 @@ Alternatively, if you want to keep low and moderate vulnerabilities as warnings,
> [!NOTE]
> MSBuild properties for message severity such as `NoWarn` and `TreatWarningsAsErrors` are not supported for packages.config projects.

## Running NuGet Audit in CI

### Separating Errors from Warnings with a Dedicated Auditing Pipeline

You can use MSBuild's conditional statements to configure a dedicated CI pipeline for running audits, without audit warnings being treated as errors in other pipelines or on local builds.
Depending on your CI system and team processes, you can have failed runs of the audit pipeline email the team, or you may have a dashboard where you can show a badge of the most recent run of the pipeline.
#### Excluding advisories

Like many things in programming, there are multiple ways to achieve the outcome.
One option is to treat NuGet Audit warnings as errors only in an audit pipeline.
You can exclude advisories by adding a new `NuGetAuditSuppress` MSBuild item for each advisory.
Define a `NuGetAuditSuppress` item with the `Include=` metadata set to the advisory URL you wish to suppress.

```xml
<PropertyGroup>
<NuGetAuditCodes>NU1900;NU1901;NU1902;NU1903;NU1904;NU1905</NuGetAuditCodes>
<WarningsAsErrors Condition=" '$(AuditPipeline)' == 'true' ">$(WarningsAsErrors);$(NuGetAuditCodes)</WarningsAsErrors>
<WarningsNotAsErrors Condition=" '$(AuditPipeline)' != 'true' ">$(WarningsNotAsErrors);$(NuGetAuditCodes)</WarningsNotAsErrors>
</PropertyGroup>
```

Then in your pipeline, you run restore specifying the property used by the condition.
For example, using GitHub Actions syntax:

```yml
- name: Restore with NuGet Auditing
run: dotnet restore -p:AuditPipeline=true
<ItemGroup>
<NuGetAuditSuppress Include="https://github.com/advisories/XXXX" />
</ItemGroup>
```

The property name `AuditPipeline` is only an example, and you can customize it as you wish, as long as the name is the same in both the MSBuild condition and the command line.
MSBuild also uses environment variables when reading a property that has not yet been defined, so an environment variable is an alternative to the command line parameter.

By using conditions to selectively cause NuGet Audit warnings to fail a restore, you can have a dedicated pipeline to check packages for known vulnerabilities, while preventing new security advisories from blocking your bug fixes at inconvenient times.
Keeping NuGet Audit warnings enabled for local builds allows developers to get a non-blocking notification about new security advisories and can encourage upgrading package versions to fix the vulnerabilities more quickly than waiting for someone to check the audit pipeline status.

### Ensure restore audited projects

NuGet in MSBuild 17.13 and .NET 9.0.200 added output properties `RestoreProjectCount`, `RestoreSkippedCount` and `RestoreProjectsAuditedCount` on the restore task.
This can be used to enforce that audit ran during a restore.
Note that these output properties are not available with [static graph restore](../reference/msbuild-targets.md#restoring-with-msbuild-static-graph-evaluation).

Since MSBuild is a scripting language, this can be achieved a number of different ways, but also has the same restrictions as MSBuild has.
One example is to create a file *Directory.Solution.targets* in the same directory as your solution file, whose contents has a target similar to the following.
Note that *Directory.Build.props* is commonly used, but is imported by projects.
However, NuGet's restore target and task runs at the solution level, so needs to be in MSBuild's solution extensibility file, not the project/build file.

```xml
<Project>
<Target Name="AssertRestoreTaskOutputProperties"
AfterTargets="Restore"
Condition="'$(CI)' == 'true'">
<Error
Condition="'$(RestoreProjectsAuditedCount)' != '$(RestoreProjectCount)'"
Text=""Restore did not audit every project in the solution. Expected: $(RestoreProjectCount) Found: $(RestoreProjectsAuditedCount)"" />
</Target>
</Project>
```
Similar to the other NuGet audit configuration properties, `NuGetAuditSuppress` items can be defined at the project or repository level.

Depending on your use-case, you may wish to use condition `'$(RestoreProjectCount)' != '$([MSBuild::Add($(RestoreProjectsAuditedCount), $(RestoreSkippedCount))'` on the error message, to account for projects that restore skipped because they were already up to date.
Similarly, think about if you want this error to happen everywhere, or only in CI pipelines, and what environment variables are defined in your CI environment, and factor this into the target's condition.
Again, since MSBuild is a scripting language, you can use any of its capabilities to customize your repo however you want.
Viewing [MSBuild's metaproj](/visualstudio/msbuild/how-to-build-specific-targets-in-solutions-by-using-msbuild-exe#troubleshooting) and [binlogs](/visualstudio/msbuild/msbuild-command-line-reference#switches-for-loggers) are useful to develop and troubleshoot solution level targets.
`NuGetAuditSuppress` is available for PackageReference projects starting from [NuGet 6.11, Visual Studio 17.11, and the .NET 8.0.400 SDK](../release-notes/NuGet-6.11.md).
It is available for packages.config from [Visual Studio 17.12 and NuGet 6.12](../release-notes/NuGet-6.12.md).

## `dotnet list package --vulnerable`
##### When to exclude advisories

Once a project is successfully restored, [`dotnet list package`](/dotnet/core/tools/dotnet-list-package) has a `--vulnerable` argument to filter the packages based on which packages have known vulnerabilities.
Note that `--include-transitive` is not default, so should be included.
In scenarios where you have analyzed a specific advisory and have determined that it either does not apply to your scenario, or you are comfortable with the risks it imposes, you can choose to exclude specific advisories from the audit report.
Note that this would completely suppress the advisories, even for packages that share the advisory that may not be part of your project.
`NuGetAuditSuppress` should be considered a last resort for managing advisories.

## Actions when packages with known vulnerabilities are reported

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 this situation, update the package version to one that fixes the vulnerability.
The easiest case is when a package you reference directly has the known vulnerability.
In this situation, update the package version to one that fixes the vulnerability.

Package vulnerabilities may be reported in both direct and transitive package references.
The action you take to resolve may be different because of that.

### Security vulnerabilities found with updates

If security vulnerabilities are found and updates are available for the package, you can either:
If security vulnerabilities are found and updates are available for the package, you can do one of the following:

- Edit the `.csproj` or other package version location (`Directory.Packages.props`) with a newer version containing a security fix.
- Use the NuGet package manager user interface in Visual Studio to update the individual package.
- Run the `dotnet package update --vulnerable` command to update all vulnerable packages in a project to the first version without known vulnerabilities.
- Run the `dotnet package update` or `dotnet package add` commands with the respective package ID to update to the latest version. Use [`dotnet add package` when using .NET 9 or earlier](/dotnet/core/whats-new/dotnet-10/sdk#more-consistent-command-order).
- Use the NuGet Model Context Protocol (MCP) server that has the ability to update packages in your project to versions that resolve known vulnerabilities.
See [Fixing package vulnerabilities](NuGet-MCP-Server.md#fixing-package-vulnerabilities) for more information.

#### Transitive Packages

Expand Down Expand Up @@ -254,10 +197,6 @@ If you mouse hover over a package in the package list, the tooltip will include

![Visual Studio Package Manager UI tooltip](media/pm-ui-transitive-tooltip-1.png)

### Use Copilot to update packages
NuGet has released a Model Context Protocol (MCP) server that has the ability to update packages in your project to versions that resolve known vulnerabilities.
See [Fixing package vulnerabilities](NuGet-MCP-Server.md#fixing-package-vulnerabilities) for more information.

### Security vulnerabilities found with no updates

In the case that a known vulnerability exists in a package without a security fix, you can do the following.
Expand Down Expand Up @@ -290,7 +229,67 @@ On NuGet.org, you can navigate to the package details page and click `Report pac
If no security vulnerabilities are found, this means that packages with known vulnerabilities were not found in your package graph at the present moment of time you checked.
Since the advisory database can be updated at any time, we recommend regularly checking your `dotnet restore` output and ensuring the same in your continuous integration process.

## Summary
## Running NuGet Audit in CI

### Separating Errors from Warnings with a Dedicated Auditing Pipeline

You can use MSBuild's conditional statements to configure a dedicated CI pipeline for running audits, without audit warnings being treated as errors in other pipelines or on local builds.
Depending on your CI system and team processes, you can have failed runs of the audit pipeline email the team, or you may have a dashboard where you can show a badge of the most recent run of the pipeline.

Like many things in programming, there are multiple ways to achieve the outcome.
One option is to treat NuGet Audit warnings as errors only in an audit pipeline.

```xml
<PropertyGroup>
<NuGetAuditCodes>NU1900;NU1901;NU1902;NU1903;NU1904;NU1905</NuGetAuditCodes>
<WarningsAsErrors Condition=" '$(AuditPipeline)' == 'true' ">$(WarningsAsErrors);$(NuGetAuditCodes)</WarningsAsErrors>
<WarningsNotAsErrors Condition=" '$(AuditPipeline)' != 'true' ">$(WarningsNotAsErrors);$(NuGetAuditCodes)</WarningsNotAsErrors>
</PropertyGroup>
```

Then in your pipeline, you run restore specifying the property used by the condition.
For example, using GitHub Actions syntax:

Security auditing features are crucial for maintaining the security and integrity of software projects.
These features provide you with an additional layer of protection against security vulnerabilities and ensures that you can use open source packages with confidence.
```yml
- name: Restore with NuGet Auditing
run: dotnet restore -p:AuditPipeline=true
```

The property name `AuditPipeline` is only an example, and you can customize it as you wish, as long as the name is the same in both the MSBuild condition and the command line.
MSBuild also uses environment variables when reading a property that has not yet been defined, so an environment variable is an alternative to the command line parameter.

By using conditions to selectively cause NuGet Audit warnings to fail a restore, you can have a dedicated pipeline to check packages for known vulnerabilities, while preventing new security advisories from blocking your bug fixes at inconvenient times.
Keeping NuGet Audit warnings enabled for local builds allows developers to get a non-blocking notification about new security advisories and can encourage upgrading package versions to fix the vulnerabilities more quickly than waiting for someone to check the audit pipeline status.

### Ensure restore audited projects

NuGet in MSBuild 17.13 and .NET 9.0.200 added output properties `RestoreProjectCount`, `RestoreSkippedCount` and `RestoreProjectsAuditedCount` on the restore task.
This can be used to enforce that audit ran during a restore.
Note that these output properties are not available with [static graph restore](../reference/msbuild-targets.md#restoring-with-msbuild-static-graph-evaluation).

Since MSBuild is a scripting language, this can be achieved a number of different ways, but also has the same restrictions as MSBuild has.
One example is to create a file *Directory.Solution.targets* in the same directory as your solution file, whose contents has a target similar to the following.
Note that *Directory.Build.props* is commonly used, but is imported by projects.
However, NuGet's restore target and task runs at the solution level, so needs to be in MSBuild's solution extensibility file, not the project/build file.

```xml
<Project>
<Target Name="AssertRestoreTaskOutputProperties"
AfterTargets="Restore"
Condition="'$(CI)' == 'true'">
<Error
Condition="'$(RestoreProjectsAuditedCount)' != '$(RestoreProjectCount)'"
Text=""Restore did not audit every project in the solution. Expected: $(RestoreProjectCount) Found: $(RestoreProjectsAuditedCount)"" />
</Target>
</Project>
```

Depending on your use-case, you may wish to use condition `'$(RestoreProjectCount)' != '$([MSBuild::Add($(RestoreProjectsAuditedCount), $(RestoreSkippedCount))'` on the error message, to account for projects that restore skipped because they were already up to date.
Similarly, think about if you want this error to happen everywhere, or only in CI pipelines, and what environment variables are defined in your CI environment, and factor this into the target's condition.
Again, since MSBuild is a scripting language, you can use any of its capabilities to customize your repo however you want.
Viewing [MSBuild's metaproj](/visualstudio/msbuild/how-to-build-specific-targets-in-solutions-by-using-msbuild-exe#troubleshooting) and [binlogs](/visualstudio/msbuild/msbuild-command-line-reference#switches-for-loggers) are useful to develop and troubleshoot solution level targets.

## `dotnet list package --vulnerable`

[`dotnet list package`](/dotnet/core/tools/dotnet-list-package) has a `--vulnerable` argument to filter the packages based on which packages have known vulnerabilities.
Note that `--include-transitive` is not default, so should be included.