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!