While your software might be the best in the world, it's only as good as the libraries it uses. In this small blog post, we will discover how to check your solution for NuGet vulnerabilities or deprecated packages.
Motivation
You might check your own code for common issues like Cross-Site Scripting (XSS), SQL Injection, etc. But what about the libraries you use? They might have vulnerabilities or be deprecated. Attackers could use a supply chain attack to inject malicious code into your software.
What is a supply chain attack?
A supply chain attack is a cyber-attack that seeks to damage an organization by targeting less-secure elements in the supply chain, like, say, a third-party package.
NuGet to the rescue
Since some versions (.NET 5 SDK), NuGet will report vulnerabilities and deprecated packages on their website and, of course, also via the CLI. And this is what we will use in this blog post. We can leverage the dotnet
CLI to check for vulnerabilities and deprecated packages.
Let's create a simple project like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Data.SqlClient" Version="4.8.5" />
</ItemGroup>
</Project>
System.Data.SqlClient
in Version 4.8.5 has a known vulnerability. If you go to the NuGet website, it looks like this:
So, the website tells us that there is a vulnerability in this package and there might be a newer version available.
If we do the same with the CLI:
dotnet list package --vulnerable
This will result in:
The following sources were used:
https://api.nuget.org/v3/index.json
https://ci.appveyor.com/nuget/benchmarkdotnet
Project `Vulnerable` has the following vulnerable packages
[net8.0]:
Top-level Package Requested Resolved Severity Advisory URL
> System.Data.SqlClient 4.8.5 4.8.5 High https://github.com/advisories/GHSA-98g6-xh36-x2p7
We could leverage that in a CI/CD pipeline to check for vulnerabilities and fail the build if there are any. Currently, the CLI always returns 0 as an exit code, so we have to parse the output to check for vulnerabilities. There is a ticket on GitHub to address that issue: https://github.com/NuGet/Home/issues/11315
If you do feel it is worth having, give the ticket a thumbs up. Alternatively, you can utilize tools like grep
in your CI pipeline. Here is an example of how to do that with GitHub Actions:
- name: Check for vulnerable packages
run: |
set -e # This will cause the script to exit on the first error
OUTPUT=$(dotnet list package --vulnerable)
echo "$OUTPUT"
if echo "$OUTPUT" | grep -q 'no vulnerable packages'; then
echo "No vulnerable packages found"
else
if echo "$OUTPUT" | grep -q 'vulnerable'; then
echo "Vulnerable packages found"
exit 1
fi
fi
If you have a project with the name Vulnerable, then you have to specify a bit more of the error string, as also project names are printed to the console, which will lead to a failure if you have "MyAssembly.Vulnerable.csproj".
More things you can do
It doesn't stop here - you can also check for vulnerabilities in the dependencies of your dependencies. This is especially important if you use a lot of third-party packages.
dotnet list package --vulnerable --include-transitive
Last but not least, you can also check for deprecated packages:
dotnet list package --deprecated
Conclusion
Keep track of your dependencies. It is important to keep them up-to-date!