Automate Security Scans with Continuous Integration
There are many tools out there that help you get a quick idea of possible security issues in your code and dependencies, but how often do you run them? If you’re running a Rails app and have never run brakeman or bundler-audit, I strongly urge you to run these tools immediately. Brakeman finds common insecure coding patterns that might be exploitable in the correct context and bundler-audit checks for known vulnerabilities within your installed gem dependencies.
The premise of this blog post isn’t to teach you to run these tools, but rather to teach you how to implement these tools into your Continuous Integration service. If you’re curious of how to run these tools outside of the test suite, both tool’s READMEs are informative.
Rietta currently uses TravisCI in order to automate the running of bundler-audit
and brakeman
. We also automate rubocop
, rspec
, and many other tools. Recently, when nokogiri CVE-2017-9050 came out, all active projects of Rietta notified via a CRON Travis job that alerted us via email and via slack that our nokogiri
dependency had a vulnerability and needed to be updated.
The fix was simple, adding the following lines in our Gemfile to lock the version of nokogiri
above the exploitable version:
# intentionally locked due to nokogiri CVE-2017-9050
# https://github.com/sparklemotion/nokogiri/issues/1673
gem 'nokogiri', '>= 1.8.1'
The comments are not necessarily needed, but we like to be explicit to ensure this stays locked to keep from accidentally utilizing a vulnerable version of nokogiri
.
So how do we do it?
In travis, this configuration is actually quite simple:
.travis.yml:
language: ruby
rvm:
- 2.4.1
before_script:
# install gems manually to ensure they are installed locally
# travis won't have these, so this will install whatever the
# latest is for your Ruby version
- gem install brakeman
- gem install bundle-audit
- bundle-audit update # ensure we have the latest vulnerability database
script:
# don't use bundle exec to use locally installed versions
- brakeman -z
- bundle-audit
Note that if you want to run your test suite, you’ll need to have your pre-setup in before_script. In Rietta case, bin/setup
does all the heavy lifting of repo setup for us, so we just add bin/setup
to run in the before_script). You’ll also need to add the command you use to run your test suite. By default, bin/rake
should run your test suite.
An example of a more complete .travis.yml
might look like so:
.travis.yml:
language: ruby
rvm:
- 2.4.1
cache: bundler
addons:
postgresql: '9.4'
before_script:
- bundle exec bin/setup
- gem install bundle-audit
- bundle-audit update
script:
- bundle exec bin/rake
- bundle exec rubocop
- bundle exec brakeman -z
- bundle-audit
In addition to having this build on pushes, we also run our CI daily utilizing Travis' CRON feature. This allows us to get a daily check that will alert us if either brakeman
or bundler-audit
fail.
As demonstrated, adding security checks to your CI is can be a rather trivial, yet rewarding, feature addition. Rietta would love to hear what your security pipeline includes.