A vulnerability was recently discovered in the doorkeeper gem. It taught me the hard way how to deal with security issues in OSS, and I documented what I’ve learned in the process.
When you become aware of a vulnerability in a project you maintain, keep it private. A vulnerability shouldn’t be made public until it’s been fixed.
Rails developers may have experienced this: a new patch version of Rails is suddenly announced, and you should upgrade. What happens in such cases is:
- Someone discovers a vulnerability.
- Rails core team work with the discoverer to fix it.
- A new patch version is released for affected Rails versions.
- The vulnerability and how to upgrade is announced in Ruby on Rails Twitter account, their blog, security mailing lists, etc.
Let’s see in detail how all this happens.
Before you start fixing the bug (or while you are doing it) you should request a “CVE id”. An id can be requested from any of the “CVE Numbering Authorities”. I myself sent my request to RedHat, and Kurt Seifried provided me with an identifier in less than an hour. He hosts a wiki with more information.
CVE stands for “Common Vulnerabilities and Exposures”. This allows us to sanely talk about security issues (“issue CVE-2009-3555” instead of “the OpenSSL vulnerability, from like 2009, the DoS one… no, not that one”). CVE allows multiple vendors, products, and customers to properly track security vulnerabilities and make sure they are dealt with. CVE Identifiers are from an international information security effort that is publicly available and free to use.
The CVE report specifies:
- The project (name and related links)
- A description of the vulnerability
- Affected and fixed versions
- What’s the vulnerability’s impact (how many people are affected and how)
- What is the upgrade process
- What workarounds can users take, if any
- Any other kind of relevant information you can provide
Here is my example:
Cross-site request forgery (CSRF) vulnerability in doorkeeper 1.4.0 and earlier allows remote attackers to hijack the user's OAuth autorization code. This vulnerability has been assigned the CVE identifier CVE-2014-8144. Versions Affected: 1.4.0 and below Fixed Versions: 1.4.1, 2.0.0 ## Impact Doorkeeper's endpoints didn't have CSRF protection. Any HTML document on the Internet can then read a user's authorization code with arbitrary scope from any Doorkeeper-compatible Rails app you are logged in. ## Releases The 1.4.1 and 2.0.0 releases are available at https://rubygems.org/gems/doorkeeper and https://github.com/doorkeeper-gem/doorkeeper. ## Upgrade Process Upgrade doorkeeper version at least to 1.4.1. ## Workarounds There are no feasible workarounds for this vulnerability. ## Credits Thanks to Sergey Belov of DigitalOcean for finding the vulnerability, Phill Baker of DigitalOcean for reporting and fixing it, and to Egor Homakov of Sakurity.com for raising awareness.
Work on the vulnerability in private. Only publish the fixes when you release new patched versions of your project. This keeps people from learning about the vulnerability before it’s been fixed, potentially taking advantage from affected deploys of your software. The goal is to reach most users of your project so they can upgrade as soon as possible.
If you take too long to release, the attacker might announce it before you have a fix ready. The person who reported the vulnerability is the “white hat”. There may already be “black hats” taking advantage of it. CVE reports typically go public after 2 weeks since an id was granted to address this issue.
After you get the CVE identifier and report, the fix and releases ready, publish this information to security lists and to users of your library, as widely as you’re able to, using any communication techniques available to you.
I was advised to post doorkeeper’s report to the following lists:
- firstname.lastname@example.org Mailing list.
- ruby-security-ann Google Group.
- ruby-advisory-db GitHub project.
After all is done you can relax. Until next time!
Adding the report to
ruby-advisory-db is particularly useful for end users.
Ruby developers can use
bundler-audit, which uses
automatically alert themselves of security issues. We made
dependency in all our Rails apps by adding it to
Suspenders in version 1.19.0.
Here’s how it is set up in our Rails apps:
# Gemfile group :development do gem "bundler-audit" end # Rakefile task default: "bundler:audit" # lib/tasks/bundler_audit.rake if Rails.env.development? || Rails.env.test? require "bundler/audit/cli" namespace :bundler do task :audit do %w(update check).each do |command| Bundler::Audit::CLI.start [command] end end end end
We hook the rake task into our default test suite so that we are sure it is run often. Running this task in an app using an insecure version of Doorkeeper would print out something like:
Name: doorkeeper Version: 1.3.0 Advisory: CVE-2014-8144 Criticality: Unknown URL: https://groups.google.com/forum/#!topic/ruby-security-ann/5_VqJtNc8jw Title: Cross-site request forgery (CSRF) vulnerability in doorkeeper 1.4.0 and earlier. Solution: upgrade to ~> 1.4.1, >= 2.0.0
Don’t do what I did with Doorkeeper:
- Tell the person who reports the vulnerability to send a pull request, which is public.
- Wait until the next scheduled release to bump the patch version with the fix.
- Keep it private, following the guidelines described above, making it public only after the fix is released.
- Release the fix as soon as possible.
A week after the Doorkeeper fix, Egor Homakov raised awareness, calling users to upgrade, and myself to finally release. Thank you Egor for your pat on the back that morning and for the ongoing help you are providing.