Checking your solution for NuGet vulnerabilities or deprecated packages

5/2/2024

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:

Nuget Website

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!

Anonymous test data with AutoFixture

Often times we have unit or integration tests that rely on some input data. The easiest solution is just to take some hard-coded values and move on with life. This has some major downsides:

Giving specific values in a test carries meaning, but we are often times not interested in that. We just need to pass the object around to fulfill the API. Also the simplest solution to fulfill your test is literally checking against those values.

Here is an elegant solution to that problem: AutoFixture. I will show you what it can do, especially in combination with xUnit.

Centralize your packages in .NET with NuGet

A feature that isn't really new but still didn't get my attention until recently is: "Central Package Management". So let's have a look at this in this blog post.

UNO Platform - Build a Todo App - Part 3

In the third part of our small mini series: "Building an todo app with the Uno Platform" we will dive deeper into creating a modal dialog where we can enter the details of our todo item. We will see how we can import additional Nuget packages and how we can leverage validation.

An error has occurred. This application may no longer respond until reloaded. Reload x