DEV Community

Gaberial Sofie
Gaberial Sofie

Posted on

Governance Risk Is Supply-Chain Risk: Auditing Every Dependency After the RubyGems Hostile Takeover

The exposure

In September 2025 the people who built and ran RubyGems and Bundler lost administrative access to the infrastructure they maintained, and several publicly quit. One side called it a hostile takeover; the other called it responsible stewardship. The verdict is not the point. The exposure is: infrastructure serving billions of downloads a month — the infrastructure every bundle install, every deploy, every CI run reaches into — demonstrated that control over the packages your builds depend on can change hands overnight.

Framed as a security problem, the rubygems hostile takeover is a governance-risk event, and governance risk is supply-chain risk that no vulnerability scanner will ever flag. A CVE scanner tells you a dependency has a known flaw; it says nothing about whether that dependency's maintainers just walked out or its publishing rights just moved to someone you did not vet. My company does not contribute to RubyGems — we only consume it, which means we had silently accepted a dependency on both the packages and the people, and the crisis made that dependency visible. The Register covered the control fight as it erupted, Ruby Central later published its own RubyGems Fracture Incident Report owning the execution mistakes, and I worked through a thorough third-party first-person timeline of what one engineer changed in response → while treating our own exposure as a fire drill rather than a hot take.

Threat model

The timeline matters only insofar as it names the threats. Between September 9 and 19, the GitHub org was renamed, maintainers were removed, administrative access to the RubyGems, Bundler, and RubyGems.org teams was revoked — including control of the bundler and rubygems-update gems themselves — and the creator of Bundler announced the team was effectively finished. From that, the concrete threats:

  • Publishing rights changing hands overnight. Control over the exact packages your builds pull can move to a different party without your consent or knowledge. If your security model assumes the right people hold the keys, it is not a model — it is a hope. Ruby Central's own incident report concedes the foundation "lacked the structural ability to make this change directly," i.e. an informal power structure that a single actor could reconfigure.
  • Maintainer-exodus as a failure mode. The people who understand a critical dependency's internals can all leave at once. A healthy maintainer team is itself a dependency, and its collapse is a real failure mode — a bus-factor risk at ecosystem scale.
  • Registry availability during the incident. If RubyGems.org had gone dark or a gem had been yanked mid-fracture, builds that fetch from upstream at deploy time would have failed. Reachability of a third party you do not control sits on your critical path.
  • Funding-pressure-driven consolidation. Reporting since made clear how much funding pressure sat underneath the fight — The Register relayed developer Joel Drapper's allegation that Shopify pressed for consolidated control of the bundler and rubygems-update gems under threat of pulled funding. Commercial leverage over volunteer infrastructure is a governance attack surface in its own right.
  • Ecosystem split. The ousted maintainers did not disappear; Martin Emde announced The Gem Cooperative (gem.coop), a community-run mirror, which The Register covered as the maintainers' new home. "Which registry does our bundle install actually hit" went from a question I would have shrugged at to a line item.

The organizing principle: reproducibility is resilience. If a build needs the internet — and a particular governance arrangement — to be calm in order to succeed, it will fail when they are not.

Controls we added

I gave the drill one week and one goal: make sure a governance blowup or a bad actor upstream could neither stop us shipping nor poison our builds.

Control 1 — freeze the ground we stand on

  • Committed and audited Gemfile.lock so every version and platform is pinned, not floating into production.
  • Vendored the critical path. bundle cache copies every .gem into vendor/cache and, per the docs, makes future installs "use the gems in the cache in preference to the ones on rubygems.org"; bundle config set cache_all true keeps git and path gems there too. If RubyGems.org went dark or a gem was yanked mid-incident, deploys still work from the cache. This directly retires the registry-availability threat.
  • Pinned git dependencies to commit SHAs, never bare branch names. A branch can be force-pushed under new ownership; a SHA cannot be quietly swapped — which addresses the "control changed hands" threat at the integrity level.

Control 2 — inventory governance risk, not just CVE risk

Because scanners like bundler-audit (which checks Gemfile.lock against the ruby-advisory-db) are silent on governance, I built a checklist and ran our top dependencies through it:

  • Who actually controls publishing rights to this package today?
  • How many maintainers — is it a bus-factor of one?
  • Has ownership or org name changed recently?
  • Is there a funded, formal body behind it, or informal goodwill?
  • If it vanished tomorrow, what is our replacement path?

That last question turns a vague anxiety into a ranked list of things to fix, which is the difference between worrying about governance risk and actually managing it.

Control 3 — reduce the surface

Fewer upstreams means fewer governance fires can burn you. I pruned unused and transitive bloat and added a "why this dependency, and who is behind it?" note to code review for anything new — the same hygiene the ecosystem needs at the macro level, applied to our own repo. Least privilege for dependencies: adopt only what you can justify and account for.

Verifying the controls, not just shipping them

A control the team does not believe in gets removed the first time it is inconvenient, so the verification here was as much organizational as technical. I made the risk concrete with three questions borrowed from the crisis: if the maintainers of our single most critical dependency all quit tomorrow, what breaks and how fast; who can publish a new version of that package right now, and do we trust the process that grants them that power; and if that package got hijacked and shipped a malicious release, would our pipeline catch it before production. For most dependencies the honest first answer was "we don't know," and "we don't know" is the actual risk — so the checklist and the vendoring exist to convert those unknowns into documented, tested answers. The vendoring in particular is verifiable in the most direct way: a build run with upstream network access blocked either succeeds from vendor/cache or it does not, and ours does. Unexpectedly, "we are hardening against a real, recent, widely-reported failure in our supply chain" turned out to be the easiest resilience work I have ever had to justify to leadership.

Residual risk / what we're still watching

The drill meaningfully reduced our exposure to an upstream governance shock, but it did not make us independent of the ecosystem, and the edges deserve honesty.

  • Vendored gems drift and stale. vendor/cache protects availability, but a frozen cache also stops receiving security updates; a vulnerability disclosed in a vendored gem is now on us to notice and refresh. Vendoring trades an availability risk for a patch-currency obligation, so we pair it with scheduled re-audits rather than treating the cache as done.
  • Scanners still cannot see governance. The checklist is a manual control against a threat no tool flags, which means it decays unless it is re-run. We re-inventory the top dependencies periodically, because ownership and maintainer health change quietly between reviews.
  • The ecosystem split is unresolved. With gem.coop now standing alongside RubyGems.org, "which registry are we actually trusting, and what is its provenance" is an ongoing decision, not a settled one. We are watching how it resolves without letting our builds depend on it resolving well.
  • Transitive dependencies we do not control. We can inventory our direct dependencies' governance, but the long tail of transitive gems carries the same risk with far less visibility. That surface is the hardest residual to close, and it is where we assume the next surprise lives.
  • Our second line still assumes a first line. Vendoring and pinning protect us from upstream disappearing, not from a malicious release we vendor before anyone notices it is malicious — that gap is covered by scanning and review, which are themselves only as current as their data.

The durable lesson is that you depend on people, not just packages, and that a small group quietly holds up infrastructure the whole ecosystem leans on. When that group fractures, everyone downstream discovers exactly how much they were depending on trust they never examined. What we keep watching is that trust — deliberately, on calm afternoons, rather than during the next incident.

Sources & further reading

Top comments (0)