Securing .NET Applications: Preventing Threats Through Package Audits

Summary
Lets start this article with a few important questions !
- Have you ever faced a production issue due to a vulnerable package?
- Are you confident your CI/CD pipeline can catch outdated or risky dependencies?
- How do you currently monitor package vulnerabilities in your projects?
These are critical questions every developer and team should ask themselves. Addressing these concerns proactively can save you from potential security breaches and ensure the reliability of your applications.
We often trust third-party NuGet
packages to accelerate development—but with that trust comes risk. Many of these packages may carry known security vulnerabilities, and if left unchecked, they can become a backdoor into your application. This is where vulnerability detection in .NET
projects becomes critical.
Starting with .NET SDK 5.0.200
, Microsoft introduced a built-in auditing command:
Try running the below command in your dotnet project and see what happens
dotnet list package --vulnerable
Code Sample #1 : Command to check for vulnerable packages
This command scans both direct and transitive NuGet
dependencies for known security issues using Microsoft’s advisory database. It flags packages with vulnerabilities, categorizing them by severity (Low to Critical), and provides advisory URLs to investigate further.
But detection is only step one.
Vulnerability checks should be automated into your build or deployment workflows. Failing a build when vulnerabilities are found prevents insecure code from reaching production. Simple shell or PowerShell scripts can be used to enforce this in local or CI pipelines without relying on GitHub or external tools.
Equally important is the role of the .csproj file—this file acts as the source of truth for all your package references. A single vulnerable package listed here, directly or indirectly, can compromise your entire application.
NugetAudit to the rescue!
NuGet 6.8
introduced the NuGetAudit
MSBuild property, which enhances vulnerability detection during restore/build time. When set to true
, NuGetAudit
performs an audit of your project's NuGet
dependencies and generates warnings for any detected vulnerabilities. This allows you to identify and address security issues before your application is deployed.
We are using a sample repo here which which uses below packages
Refit
version 7.2.1 which has Critical vulnerabilityNewtonsoft.Json
version 12.0.3 which has High vulnerability
To enable NuGetAudit
, we can add the following to our .csproj
file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NugetAudit>true</NugetAudit>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Refit" Version="7.2.1" />
</ItemGroup>
</Project>
Code Sample #2 : Example .csproj file with NuGetAudit enabled
When NuGetAudit
is enabled, the build process will generate warnings for any NuGet
packages with known vulnerabilities. These warnings will include information about the vulnerability, such as the severity and the affected package version.
You can configure the level of detail in the NuGet
audit warnings by using the NuGetAuditLevel
property. This property accepts the following values:
None
: No audit warnings are displayed.Low
: Only warnings for vulnerabilities with a severity of Low or higher are displayed. This is default value.Moderate
: Only warnings for vulnerabilities with a severity of Moderate or higher are displayed.High
: Only warnings for vulnerabilities with a severity of High or Critical are displayed.Critical
: Only warnings for vulnerabilities with a severity of Critical are displayed.
Lets explore some more scenarios
Disabling the audit mode
When We disbale the auditing by setting NuGetAudit
To false and try to build / restore
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NugetAudit>false</NugetAudit>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Refit" Version="7.2.1" />
</ItemGroup>
</Project>
Code Sample #2 : Example .csproj file with NuGetAudit disabled

Enabling the audit mode
Lets enable the auditing by setting NuGetAudit
To true and try to build / restore
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NugetAudit>true</NugetAudit>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Refit" Version="7.2.1" />
</ItemGroup>
</Project>
Code Sample #3 : Example .csproj file with NuGetAudit enabled

As we can see the build is warning about both the critical and high severity level packages.
Depending on security guidelines we may want to only flag certain severity level
Setting the severity level
Depending on security guidelines for out project we may want to only flag certain severity level and above. For this article lets assume, we only want to warn about critial vulnerabilities and leave the rest.
Lets set the severity level for our audit by setting NuGetAudit
To true and try to build / restore
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NugetAudit>true</NugetAudit>
<NugetAuditLevel>critical</NugetAuditLevel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Refit" Version="7.2.1" />
</ItemGroup>
</Project>
Code Sample #4 : Example .csproj file with NugetAuditLevel defined

As we can see the build is warning about only the critical severity level package(s).
Enforcing build failure for vulnerabilities
Now, warning are good but they can be ignored/missed allowing vulnerabilities to creep into the production code. To prevent this, there is another msbuild property WarningsAsErrors
that can help by treating specified warnings codes as errors resulting in build failure. Refer the below table to such warning codes
Warning Code | Reason |
---|---|
NU1900 | Error communicating with package source, while getting vulnerability information. |
NU1901 | Package with low severity detected |
NU1902 | Package with moderate severity detected |
NU1903 | Package with high severity detected |
NU1904 | Package with critical severity detected |
NU1905 | An audit source does not provide a vulnerability database |
Lets set critical warning as error for our audit by setting WarningsAsErrors
To true and try to build / restore
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NugetAudit>true</NugetAudit>
<NugetAuditLevel>critical</NugetAuditLevel>
<WarningsAsErrors>NU1904;</WarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Refit" Version="7.2.1" />
</ItemGroup>
</Project>
Code Sample #5 : Example .csproj file with WarningsAsErrors defined

As we can see the build is warning about only the critical severity level package(s).
Conclusion
In conclusion, vulnerability detection in .NET
projects is a critical aspect of modern software development. By leveraging the built-in auditing command and the NuGetAudit MSBuild property, developers can proactively identify and address security vulnerabilities in their applications. This not only helps to protect sensitive data but also ensures compliance with security standards and best practices.
By integrating these tools into your development workflow, you can significantly reduce the risk of security breaches and enhance the overall security posture of your .NET
applications.
Integrating these tools into your CI/CD build pipelines ensures that vulnerabilities are detected and addressed early, preventing insecure code from being deployed to production systems.
Thats about it for this article. Hope you liked it.
Thanks for reading through. Please share feedback, if any, in comments or on my email ajay.a338@gmail.com