<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thoughtbot="https://thoughtbot.com/feeds/">
  <title>Giant Robots Smashing Into Other Giant Robots</title>
  <subtitle>Written by thoughtbot, your expert partner for design and development.
</subtitle>
  <id>https://robots.thoughtbot.com/</id>
  <link href="https://thoughtbot.com/blog"/>
  <link href="https://feed.thoughtbot.com" rel="self"/>
  <updated>2026-04-21T00:00:00+00:00</updated>
  <author>
    <name>thoughtbot</name>
  </author>
<entry>
  <title>Let's enable MFA for all Ruby gems</title>
  <link rel="alternate" href="https://thoughtbot.com/blog/lets-enable-mfa-for-all-ruby-gems"/>
  <author>
    <name>Matheus Richard</name>
  </author>
  <id>https://thoughtbot.com/blog/lets-enable-mfa-for-all-ruby-gems</id>
  <published>2026-04-21T00:00:00+00:00</published>
  <updated>2026-04-24T19:37:24Z</updated>
  <content type="html">&lt;p&gt;A few weeks ago, Axios, the popular HTTP client for JavaScript, &lt;a href="https://socket.dev/blog/axios-npm-package-compromised"&gt;suffered a
supply chain attack on
NPM&lt;/a&gt;. 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.&lt;/p&gt;

&lt;p&gt;Not long before that, LiteLLM, a popular Python AI gateway, &lt;a href="https://docs.litellm.ai/blog/security-update-march-2026"&gt;had a similar
incident on
PyPI&lt;/a&gt;. Compromised
credentials were used to push malicious packages that harvested environment
variables, SSH keys, cloud credentials, and database passwords.&lt;/p&gt;

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

&lt;p&gt;Ruby is equally vulnerable to this type of attack&lt;/p&gt;
&lt;h2 id="rubygems-is-not-immune"&gt;
  
    RubyGems is not immune
  
&lt;/h2&gt;

&lt;p&gt;RubyGems hasn’t had a major attack like this &lt;em&gt;yet&lt;/em&gt;, 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) &lt;a href="https://x.com/nateberkopec/status/2039805831399788876"&gt;estimates that 75% of the gems on
RubyGems are vulnerable to this type of
attack&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There’s already been some progress. &lt;a href="https://blog.rubygems.org/2022/08/15/requiring-mfa-on-popular-gems.html"&gt;Since 2022, RubyGems has required MFA for
the most popular gems&lt;/a&gt;,
those with more than 180 million total downloads. In practice, that threshold
covers about 370 gems out of over 190,000 on RubyGems.org. The heaviest-hit
packages are protected, but the long tail of gems (and the transitive
dependencies they pull in) is still wide open.&lt;/p&gt;

&lt;p&gt;The fix is straightforward: gems can &lt;a href="https://guides.rubygems.org/mfa-requirement-opt-in/"&gt;require multi-factor authentication
(MFA)&lt;/a&gt; for all pushes by
adding a single line to their gemspec:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"rubygems_mfa_required"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After releasing a new version with this set, RubyGems.org will reject any &lt;code&gt;gem push&lt;/code&gt; 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.&lt;/p&gt;

&lt;aside class="info"&gt;
  &lt;p&gt;If you publish your gem from CI, you might be wondering how MFA fits into an automated release workflow. The answer is &lt;a href="https://guides.rubygems.org/trusted-publishing/"&gt;Trusted Publishing&lt;/a&gt;, which lets RubyGems.org authenticate your CI provider via OIDC instead of a long-lived API key. MFA and Trusted Publishing are complementary: MFA protects interactive pushes, and Trusted Publishing removes the need for shareable credentials in CI.&lt;/p&gt;
&lt;/aside&gt;
&lt;h2 id="what-you-can-do"&gt;
  
    What you can do
  
&lt;/h2&gt;

&lt;p&gt;The good thing about open source is that we can all help make it more secure.
Here’s what I propose:&lt;/p&gt;
&lt;h3 id="1-audit-your-app39s-gems"&gt;
  
    1. Audit your app’s gems
  
&lt;/h3&gt;

&lt;p&gt;Nate wrote an &lt;a href="https://gist.github.com/nateberkopec/ab12bbc2ddf39868c4633422904475af"&gt;audit
script&lt;/a&gt;
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.&lt;/p&gt;
&lt;h3 id="2-open-prs-on-gems-you-use"&gt;
  
    2. Open PRs on gems you use
  
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;
&lt;h3 id="3-enable-mfa-on-gems-you-maintain"&gt;
  
    3. Enable MFA on gems you maintain
  
&lt;/h3&gt;

&lt;p&gt;If you maintain any gems, add &lt;code&gt;rubygems_mfa_required&lt;/code&gt; to your gemspec and make
sure all owners on RubyGems.org have MFA enabled on their accounts.&lt;/p&gt;
&lt;h3 id="4-join-the-conversation"&gt;
  
    4. Join the conversation
  
&lt;/h3&gt;

&lt;p&gt;A fellow thoughtbotter &lt;a href="https://github.com/rubygems/roadmap/issues/14"&gt;opened an issue on the RubyGems
roadmap&lt;/a&gt; to start planning a
path toward requiring MFA for all gems. It floats a few ideas: progressively
lowering the download threshold, requiring MFA for all new gems, and more. If
you have thoughts on how to get there, or just want to voice support, jump in.&lt;/p&gt;
&lt;h2 id="it-takes-a-community"&gt;
  
    It takes a community
  
&lt;/h2&gt;

&lt;p&gt;I’ve been opening PRs on &lt;a href="https://github.com/thoughtbot/factory_bot/pull/1814"&gt;thoughtbot
gems&lt;/a&gt; and &lt;a href="https://github.com/excid3/noticed/pull/578"&gt;other open
source projects&lt;/a&gt;, and I encourage
you to do the same. Maintainers have been receptive, so these PRs tend to get
merged quickly. I also got &lt;a href="https://github.com/ruby/rubygems/pull/9487"&gt;a PR merged on
Bundler&lt;/a&gt; adding a commented-out
&lt;code&gt;rubygems_mfa_required&lt;/code&gt; line to the &lt;code&gt;bundle gem&lt;/code&gt; template to nudge authors of
new gems to enable this.&lt;/p&gt;

&lt;p&gt;If we all do our part, we can make the Ruby ecosystem safer for everyone. Let’s
get to work!&lt;/p&gt;

&lt;aside class="related-articles"&gt;&lt;h2&gt;If you enjoyed this post, you might also like:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://thoughtbot.com/blog/this-week-in-open-source-6-30"&gt;This Week in Open Source (June 30, 2023)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thoughtbot.com/blog/a-healthy-bundle"&gt;A Healthy Bundle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thoughtbot.com/blog/the-journey-to-ruby-1-9"&gt;The Journey to Ruby 1.9 &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/aside&gt;
</content>
  <summary>Supply chain attacks are getting more common. RubyGems might be next. Here's how to help the ecosystem be safer.</summary>
  <thoughtbot:auto_social_share>true</thoughtbot:auto_social_share>
</entry>
</feed>
