Ruby Gems Supply Chain Vulnerability
Every Ruby on Rails application depends on Ruby Gems, the third party open source libraries that make development possible. A brand new Ruby on Rails 6 application, with default options, depends upon 75 Gems before the developer makes any customizations to the app! These Gems are produced by volunteer open source maintainers, many of whom are not paid anything to work on open source, and distributed for free via rubygems.org. This is a fantastic resource that makes it possible to create so many good Ruby-based applications with minimum effort re-inventing the wheel. However, how is a developer to know the Gems he or she has in a project are in fact safe.
There have been malicious backdoors distributed in multiple Gems this year. These supply chain attacks have been detected and remediated by the RubyGems community, but it will happen again. Let’s look at the patterns common among the malicious Gems and the how you can go about protecting your own application.
Review of Malicious Gem Attack Patterns
1. Backdoors in Popular Gems Distributed via Compromised Maintainer Credentials
In 2019, malicious backdoors were distributed of three popular, mainstream Gems. In these incidents a malicious attacker compromised the credentials of legitimate Gem maintainers and used those to push malicious copies whose code did not match the version in the open source projects' github.com accounts.
Month | Gem | Version | CVE | CVSS Score |
---|---|---|---|---|
April 2019 | bootstrap-sass | 3.2.0.3 | CVE-2019-10842 | 10.0 |
July 2019 | strong_password | 0.0.7 | CVE-2019-13354 | 7.5 |
August 2019 | rest-client | 1.6.10, 1.6.11, 1.6.12, 1.6.13, 1.6.14 | CVE-2019-15224 | 7.5 |
In these three cases, credential theft was involved and if the maintainers had 2FA enabled then the attack would have not succeeded in the way it did.
Chris Choi made the Case for 2FA, Post Rest-client Gem CVE on this blog two weeks ago. The need for 2FA is a mainstream view among security professionals. It is not enough that RubyGems.org has made 2FA available as an option, we need to increase the number of maintainers who use it.
2. Malicious Typo-Squatted / Soundalike Gems
In addition to the Rest-client Gem attack described above, 10 other Gems were yanked by RubyGem.org volunteers after malicious backdoor code was discovered. This was reported in the article Backdoor code found in 11 Ruby libraries (zdnet.com).
These typo-squat attacks were different because the malicious actor cloned old Gems that had not been updated in years and then published a brand new Gem under his or her own credential. These Gems were not owned by the maintainers of the legitimate Gem but rather by the attacker him or herself. These typo-squatted versions were presumably published with the hopes that people would install and use the backdoored version instead of the much older legitimate version. This presumably capitalizes on the bias of many Ruby developers for cutting edge, more recently updated code.
Based on my own analysis of publicly available data, with the exception of awesome-bot and coin_base, none of these typo-squatted Gems had been updated in years.
Malicious Gem Name | Cloned Legitimate Gem | Age Since Legitimate Update |
---|---|---|
capistrano-colors | capistrano_colors | 7 years 10 mons 11 days |
doge-coin | doge_coin | 5 years 5 mons 7 days |
lita_coin | lita-coin | 5 years 4 mons 19 days |
blockchain_wallet | blockchain-wallet | 5 years 3 mons 21 days |
omniauth_amazon | omniauth-amazon | 3 years 4 mons 3 days |
coming-soon | coming_soon | 2 years 2 mons 13 days |
coin_base | coinbase | 5 mons 15 days |
awesome-bot | awesome_bot | -1 mons -1 days |
The attacker cloned all the metadata about the Gems, the description, the authors, everything. It is easy for someone setting up a project with one of these to be fooled to use the malicious one instead of the legitimate Gem. These malicious Gems capitalized on confusion between dashes (-) vs underscores (_), for which there is no standard among Gem publishers.
3. Maintainership Transfer to a Malicious Actor
I am not aware of a Ruby Gems specific case where a malicious actor took over maintainership from a legitimate maintainer who wished to step away from open source. It has happened in other ecosystems, such as open source web browser extensions. Nothing prevents it from happening in Ruby Gems.
How to Protect Your Project
In light of the supply chain vulnerabilities present in the RubyGems ecosystem, there are steps you can personally take to protect yourself from many of these issues. The primary ways you can protect yourself are to:
-
Minimize dependency on third party Gems
- Every dependency is an entanglement with code outside of your control that introduces brittleness
- For very simple functionality, it’s often better to write the code yourself in your own project rather than include a third party Gem
-
Run bundler-audit and make it part of your CI/CD
-
Carefully review Gems that you do choose to include
- consider the age and number of downloads of the Gem
- search for variations and see if it appears to be squatting on a typo for a more popular Gem
- there is some safety in waiting to upgrade to a new release unless you must upgrade to patch a known CVE that is reported by bundler-audit
-
Avoid using the
~>
,>=
, and>
operators in your Gemfile, preferring to instead specific specific versions of each Gem -
Update specific Gems intentionally like
bundle update nokogiri
and avoid bulk updating via runningbundle update
Software update supply chain attacks have been one of the big trends in cyber crime in recent years and is expected to grow in frequency. No matter what languages you develop in, it’s important to pay attention to what software your application depends upon and the reputation and trustworthiness of the maintainers. It is important to know that just because a Gem is trustworthy today does not mean the next published version will not contain vulnerabilities or malicious code. It is best to wait a little while before upgrading to the absolute latest release of a Gem to see if others detect an issue unless, and this is important, upgrading is necessary to fix a known published vulnerability. The same is true for Node NPM and any other package ecosystems from which you obtain software dependencies.