I believe in writing high-quality Go code, and I bet you do, too. I also know I’m not a genius and can’t write high quality code all of the time. Fortunately, a number of Go tools help me write high quality code, with less time and effort. Code linters, unit tests and TDD, and continuous integration are just a few examples.
But if you’re like me, you’ve sometimes overlooked a very important, but often invisible, aspect of code quality: security.Security is a broad topic, and there are no silver bullets to write a perfectly secure application, but there are some tools that can help.
Here, I will describe Nancy, a free Go tool that can help improve the security of your Go applications by alerting you to any known vulnerabilities in your project’s dependencies. It’s very easy to incorporate Nancy into your CI pipeline and to run Nancy manually. I’ll show you how.
“Hello. I’m Nancy Drew. It’s nice to meet you. May I ask who you are?” —Nancy Drew, Nancy Drew (2007)
Reader, meet Nancy. Nancy, meet Reader.
Nancy, as you may know by reputation, is a detective. She uses Sonatype’s OSS Index to check for vulnerabilities in your Go dependencies.
Named after the fictional detective, Nancy works by scanning your Gopkg.lock file (if you use dep) or go.sum (if you use Go modules). From these files, Nancy consults the OSS Index for known vulnerabilities in your dependencies, and if any are found, an error message is reported. But enough talk, let’s take a look!
“A reporter has the right to do things an ordinary person shouldn’t.” —Nancy Drew, Nancy Drew … Reporter (1939)
As Nancy is a tool written in Go, and Go compiles to a static binary, installation is quite simple. In most cases, it’s a simple matter of downloading the pre-compiled binary to your local system.
The following commands will download version 0.1.17 into /usr/local/bin on your local system, then make it executable:
sudo curl -L -o /usr/local/bin/nancy https://github.com/sonatype-nexus-community/nancy/releases/download/v0.1.17/nancy-linux.amd64-v0.1.17
sudo chmod +x /usr/loca/bin/nancy
If you prefer to compile from source, that is of course also possible, and the instructions for this can be found in the project repository on GitHub.
Using the Go Tool Locally
“Excuse me, I have to defuse this bomb.” —Nancy Drew, Nancy Drew (2007)
With the Go tool installed, you can easily run it from within the root of your Go project:
~/go/src/github.com/<user>/<project>$ nancy Gopkg.lock
2019/12/10 17:31:02 Nancy version: v0.1.17
Assuming no vulnerabilities are found, Nancy will simply output the version number, then exit with status 0.
If you are using an insecure dependency, the output will be somewhat longer. To demonstrate, I added a known vulnerability to my Gopkg.lock file. My project doesn’t really use this dependency, but temporarily adding it to Gopkg.lock is a simple way to test that Nancy is sleuthing appropriately!
name = "github.com/bitly/oauth2_proxy"
packages = ["."]
version = "0.1.17"
Now when I run the same command as above, I receive the following:
~/go/src/github.com/<user>/<project>$ /usr/local/bin/nancy Gopkg.lock
2019/12/10 17:32:51 Nancy version: v0.1.17
[1/1] pkg:firstname.lastname@example.org [Vulnerable] 1 known vulnerabilities affecting installed version
[CVE-2017-1000070] URL Redirection to Untrusted Site ("Open Redirect")
The Bitly oauth2_proxy in version 2.1 and earlier was affected by an open redirect vulnerability during the start and termination of the 2-legged OAuth flow. This issue was caused by improper input validation and a violation of RFC-6819
Audited dependencies: 1, Vulnerable: 1
This is quite a bit more interesting! We’re told that github.com/bitly/oauth2_proxy, version 0.9, has a known vulnerability identified as “CVE-2017-1000070”, along with a brief description and a link to more details. Armed with this information, we can decide if and how the vulnerability affects us (are we using a 2-legged OAuth flow?) and how urgently we should upgrade to a patched version. More on responding to vulnerabilities in a moment.
“I told you this is going to be awesome.” —Nancy Drew, Nancy Drew (2007)
Now it’s time for the real fun! Fortunately, adding Nancy to your CI pipeline is just as easy as installing and running it locally. Here, I’ll describe how to configure it for Travis-CI and GitHub, but it’s easy to adapt to your CI tool and repository manager of choice.
When I set this up on my own project, I had a simple .travis.yml file that ran all the unit tests for me. It looked something like this:
- go test -race ./...
To add Nancy, I simply added an install section and the new command to run. Notice that in the install section, I specify a different location for installing the nancy binary. This is because writing to /usrlocal/bin requires root permissions, and while that can be arranged in Travis, there’s no need here. It’s easier to just place the file in a location where we have write permission and that’s already in the path. My new .travis.yml file looks like this:
- curl -L -o /home/travis/gopath/bin/nancy https://github.com/sonatype-nexus-community/nancy/releases/download/v0.1.17/nancy-linux.amd64-v0.1.17
- chmod +x /home/travis/gopath/bin/nancy
- nancy Gopkg.lock
- go test -race ./...
Now on every pull request, Nancy will perform its security scan as well as run our standard tests.
We’re Not Done Yet
“I just know that any time I undertake a case, I’m apt to run into some kind of a trap.” —Nancy Drew, Nancy Drew … Reporter (1939)
But wait, there’s more!
Running the security scan for every pull request is great and necessary, but it’s not enough. What if you deploy your project, then move on to other things for a few weeks, and in the meantime a serious security flaw is discovered in one of your dependencies? To detect such a vulnerability after the fact, it’s important to continually run Nancy on a regular basis.
Travis-CI makes this easy with their Cron Jobs feature. To configure a cron job in Travis-CI, you’ll need to visit travis-ci.com (or travis-ci.org if you’re configuring Nancy on a public project), and open your dashboard:
Next, find your project in the list of repositories, and open settings:
And finally, configure your new cron job by specifying the branch to run on (master in my example, but it might be production or dev, for example), an interval (I suggest daily), and then the option to either always run or to only run if the job hasn’t already run in the previous 24 hours.
Whenever Nancy detects a security vulnerability during the daily run, you can expect an email alerting you to the failure. That way, you can promptly upgrade the vulnerable dependency.
Nancy for GitHub Actions
“That’ll show them! I’m a political force to be reckoned with!” —Nancy Drew, Nancy Drew: Sea of Darkness (2015 video game)
Sonatype has also released Nancy for GitHub Actions, which makes it very easy to use Nancy if you’re using GitHub Actions. Just search for “nancy” in the actions marketplace.
And don’t forget to schedule your GitHub actions to run daily, too!
Nancy Found a Problem, Now What?
“Well, if you must insult me, you might at least do it in English!” —Nancy Drew, Nancy Drew: Detective (1939)
If Nancy finds a problem, don’t panic!
The first thing to do is understand the nature of the problem. Read the description provided by Nancy, as well as the details in the link Nancy provided. Just because a vulnerability is found doesn’t always mean it affects you.
While you should aim to resolve all security vulnerabilities, some, such as a theoretical denial-of-service attack under obscure conditions that don’t apply to your project, may be safe to schedule a week or two into the future. On the other hand, a more serious vulnerability that may grant unauthorized access to customer credit card data should probably be fixed immediately.
With the vulnerability’s severity in mind, you can approach a resolution thoughtfully. Often the resolution can be as simple as updating to the latest version of a dependency. In other cases, a patch may not be available (yet), which may require you to put some sort of stop-gap measure in place until your dependency solves the issue upstream. A complicated case might be when upgrading the dependency breaks backward compatibility, which may require involved refactoring of your code.
Whatever the case, arm yourself with knowledge of the vulnerability so you and your team can determine the proper course of action to mitigate the security threat.
Don’t Stop There
“Okay, if… if needing your friends means you’re a loser, then I’m the biggest, loser of all, ’cause you guys make me forget I live in this one-horse town every day.” —Nancy Drew, Nancy Drew and the Hidden Staircase (2019)
As valuable as this Go tool is, Nancy isn’t enough on its own. No single tool is. Nancy will only inform you of known vulnerabilities in your dependencies. Security in your own code is still your own responsibility! Nancy won’t protect you from SQL injection, cross-site request forgery, or alert you that you’re sending passwords in plain text, for example. You must still follow all security best practices in your own code. So don’t allow yourself or your team to be lulled into a false sense of security just because you’ve got one tool in place!
Still, Nancy is a great tool to add to your developer toolbox. I’ve seen many tools that scan for known vulnerabilities, but none so lightweight and as easy to use. In under 15 minutes, you can add some important protection to your Go projects.