Let's enable MFA for all Ruby gems

https://thoughtbot.com/blog/lets-enable-mfa-for-all-ruby-gems
Matheus Richard in Brazil

A few weeks ago, Axios, the popular HTTP client for JavaScript, suffered a supply chain attack on NPM. An attacker compromised the lead maintainer’s NPM account through social engineering and published two backdoored versions that delivered a cross-platform remote access trojan (RAT) to macOS, Windows, and Linux systems. Axios has over 100 million weekly downloads. The blast radius was enormous.

Not long before that, LiteLLM, a popular Python AI gateway, had a similar incident on PyPI. Compromised credentials were used to push malicious packages that harvested environment variables, SSH keys, cloud credentials, and database passwords.

Both attacks followed the same playbook: gain access to a maintainer’s account, then push a new version with malicious code outside of the normal release process. No code review. No CI. Just a direct publish to the package registry.

Ruby is equally vulnerable to this type of attack

RubyGems is not immune

RubyGems hasn’t had a major attack like this yet, but we should be proactive in securing the ecosystem before it happens. Nate Berkopec (maintainer of Puma and a longtime voice in the Ruby community) estimates that 75% of the gems on RubyGems are vulnerable to this type of attack.

The fix is straightforward: gems can require multi-factor authentication (MFA) for all pushes by adding a single line to their gemspec:

spec.metadata["rubygems_mfa_required"] = "true"

After releasing a new version with this set, RubyGems.org will reject any gem push from an account that doesn’t have MFA enabled. Even if an attacker compromises a maintainer’s password or API key, they still can’t publish a new version without the second factor. It doesn’t make the gem invulnerable, but it raises the bar significantly.

What you can do

The good thing about open source is that we can all help make it more secure. Here’s what I propose:

1. Audit your app’s gems

Nate wrote an audit script you can run in your project to see which gems in your Gemfile don’t require MFA on push. Run it. The results might surprise you.

2. Open PRs on gems you use

Pick one or a few gems that don’t require MFA and open a PR adding the line above to their gemspec. The change is a one-liner and the PR description mostly writes itself. You can link to this post or to the Axios incident and explain why it matters.

3. Enable MFA on gems you maintain

If you maintain any gems, add rubygems_mfa_required to your gemspec and make sure all owners on RubyGems.org have MFA enabled on their accounts.

It takes a community

I’ve been opening PRs on thoughtbot gems and other open source projects, and I encourage you to do the same. Maintainers have been receptive, so these PRs tend to get merged quickly. I also got a PR merged on Bundler adding a commented-out rubygems_mfa_required line to the bundle gem template to nudge authors of new gems to enable this.

If we all do our part, we can make the Ruby ecosystem safer for everyone. Let’s get to work!

About thoughtbot

We've been helping engineering teams deliver exceptional products for over 20 years. Our designers, developers, and product managers work closely with teams to solve your toughest software challenges through collaborative design and development. Learn more about us.