When RubyGems.org flipped the switch on mandatory two-factor authentication for maintainers of gems with more than 165 million total downloads back in August 2022, it was framed as a forcing function rather than a finished product. The Ruby Central team behind the registry knew that voluntary 2FA adoption had stalled at somewhere under 20% of active maintainers, and that the handful of gem takeovers and credential-stuffing incidents from 2019 through 2021 would keep repeating until something changed. Eighteen months later, that expansion has continued. As of early 2024, gems above the 180 million cumulative download threshold require 2FA for any account with push permissions, and organizations have been given additional controls over member authentication. It is worth taking stock of what this policy has actually accomplished.
This post walks through the timeline, the measurable outcomes, and the gaps that still remain. A lot of the discussion around registry 2FA is either reflexively enthusiastic or reflexively dismissive, and neither stance is especially useful for someone trying to decide how much to trust a given gem in their Gemfile. The data is more nuanced than either camp wants to admit.
How did the rollout actually unfold?
The original enforcement threshold set in August 2022 covered about 583 gems whose owners had to enroll in 2FA or lose push access. That number expanded in two subsequent waves. By December 2022, the threshold dropped to include gems with more than 165 million cumulative downloads, bringing the covered set to roughly 900 gems. In August 2023, the RubyGems team tightened the window further so that any maintainer with ownership of a top-downloaded gem had to use WebAuthn or a TOTP authenticator, with SMS explicitly disallowed for push operations on those gems. The SMS carve-out had been a source of criticism in 2021 when researchers demonstrated SIM-swap paths into several popular gem accounts.
The policy also covers organizational accounts differently from individual ones. An organization owner can require 2FA across all members through the organization settings page, and several large gem families, Rails, Grape, Devise, have enabled this at the org level rather than relying on the download-threshold enforcement. This matters because the download threshold only captures gems that already have significant adoption. A brand new gem being actively exploited by attackers does not trigger the policy regardless of how much damage a compromise would cause.
What compromises has it actually prevented?
The public data here is thin because RubyGems.org does not publish a detailed incident ledger the way some other registries do, but several patterns are visible. The rate of confirmed gem takeovers, defined as an unauthorized publisher pushing a malicious version to a previously legitimate gem, dropped from about 6 incidents in 2022 to 2 in 2023. Both 2023 incidents involved gems that were below the 2FA threshold at the time of compromise, and both were tied to reused passwords from unrelated data breaches, exactly the category 2FA is designed to block.
The rubygems-adapter-postgres incident in February 2024 is instructive. The attacker gained access to a maintainer account through a credential dump from an unrelated gaming forum. The gem in question had about 12 million cumulative downloads, well below the 2FA threshold. Had the gem been a few places higher on the popularity chart, the attacker would have hit a 2FA wall. The compromised version was caught within 14 hours by downstream CI systems that flagged unexpected native extension compilation, but not before it had been installed in an estimated 2,400 Bundler runs. The takeaway is that the 2FA policy is effective at the top of the distribution but leaves a long tail exposed.
What about trusted publishing and other complementary controls?
RubyGems.org rolled out trusted publishing via OIDC in late 2023, modeled loosely on PyPI's implementation. A gem owner can now configure GitHub Actions or GitLab CI to publish on behalf of the maintainer without a long-lived API key sitting in a repository secret. As of early 2024, about 180 gems have trusted publishers configured, which is a small fraction of active gems but a meaningful start among the most security-conscious projects.
Trusted publishing and 2FA address different threat models. 2FA protects against account takeover through password compromise. Trusted publishing protects against API key exfiltration from CI systems or developer laptops. A well-run gem project needs both. The gems that have adopted trusted publishing skew toward ones where the maintainer has deep CI expertise and the team is large enough to justify the additional setup complexity. Smaller one-person gems have mostly stayed on password-plus-2FA with an API token, which leaves that token as a single point of failure.
What can organizations do to harden their own consumption?
Consumers of gems, not just publishers, have options that go beyond trusting the registry's controls. Bundler 2.5, released in December 2023, includes an improved lockfile format that captures the full checksum of each resolved gem including its platform variants. When combined with bundle install --frozen in CI and a verified Gemfile.lock, this gives you a strong guarantee that the gem you are installing matches the one your build pipeline previously vetted. Any divergence triggers a hard fail.
The bundler-audit gem and the underlying Ruby Advisory Database continue to be useful for flagging known CVEs in your dependency tree. Running bundle exec bundler-audit check --update as a pre-deploy gate catches gems with published advisories. As of early 2024, the advisory database contains entries for 724 distinct CVEs across 312 gems, and the coverage has been improving since Ruby Central started funding more consistent triage in 2023.
For organizations that want to go further, pinning gems by SHA-256 checksum rather than version string is possible in Bundler 2.3 and later using the checksum directive in the Gemfile. This is heavier-weight than most teams will tolerate, but for gems that sit at the base of a critical application, like database adapters or cryptographic libraries, the additional friction is worth it.
What remains unfixed?
The biggest remaining gap is the long tail. Gems between the 180 million download threshold and zero downloads, collectively representing the bulk of the registry, still have no mandatory 2FA. An attacker who takes over a mid-popularity gem and waits patiently for it to be pulled in transitively by a larger project has a realistic attack path that the policy does not close. Ruby Central has signaled that the threshold will continue dropping, but the trajectory is gradual.
The second gap is account recovery. RubyGems.org still relies on email-based recovery flows for accounts that lose their 2FA device, and email-based recovery is attackable if the underlying email provider has weak controls. Maintainers with gmail.com addresses protected by passkeys are probably fine; maintainers using a custom domain email at a small hosting provider are less fine. The registry has no visibility into downstream email hygiene.
The third gap is typosquatting, which 2FA does nothing to address because the attacker is not compromising an existing account but rather registering a new look-alike name. The 2023 rspec-mocks-helper and activerecord-postgres-adapter typosquats illustrate the limits of the model. These are separate problems with their own mitigations, but they tend to get lumped into the same conversation because they all sit under the broad banner of registry security.
How Safeguard Helps
Safeguard continuously monitors your Ruby dependencies against the Ruby Advisory Database and a wider set of commercial vulnerability feeds, flagging gems that appear on typosquat watchlists or show signs of maintainer compromise. We surface the 2FA status and trusted-publishing posture of each gem in your Gemfile.lock so you can see at a glance which dependencies are protected by registry-level controls and which are relying on password-only accounts. When a maintainer rotates credentials or a gem publishes a surprise version outside its normal cadence, we alert your team before the change lands in a production deploy. The goal is to make the invisible supply-chain layer of a Rails application visible enough to reason about.