<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>RubyGems Blog</title>
 <link href="https://blog.rubygems.org/atom.xml" rel="self"/>
 <link href="https://blog.rubygems.org/"/>
 <updated>2026-08-06T02:13:01+00:00</updated>
 <id>https://blog.rubygems.org/</id>
 <author>
   <name>RubyGems Team</name>
   <email>support@rubygems.org</email>
 </author>

 
 <entry>
   <title>Making RubyGems Guides friendly to humans and AI</title>
   <link href="https://blog.rubygems.org/2026/08/06/making-rubygems-guides-ai-friendly.html"/>
   <updated>2026-08-06T00:00:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/08/06/making-rubygems-guides-ai-friendly</id>
   <author><name>Hiroshi SHIBATA</name></author>
   <content type="html">&lt;p&gt;The RubyGems guides at &lt;a href=&quot;https://guides.rubygems.org&quot;&gt;guides.rubygems.org&lt;/a&gt; are read by more than humans these days. AI agents fetch them to answer questions about building, publishing, and installing gems. Evil Martians’ &lt;a href=&quot;https://ruby.evilmartians.com/&quot;&gt;Ruby/Rails LLM discoverability scorecard&lt;/a&gt; asks how easily an agent can find and read Ruby documentation, and the guides had no good answer. There was no machine readable index, and no way to get a page without its navigation and markup. This week we merged three changes that close both gaps.&lt;/p&gt;

&lt;p&gt;The first change adds &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sitemap.xml&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;robots.txt&lt;/code&gt; (&lt;a href=&quot;https://github.com/rubygems/guides/pull/523&quot;&gt;rubygems/guides#523&lt;/a&gt;), giving crawlers a complete map of the site. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;robots.txt&lt;/code&gt; allows everyone, AI crawlers included. Some documentation sites have gone the other way, but these guides exist to be read, and that holds regardless of what is doing the reading.&lt;/p&gt;

&lt;p&gt;The second adds &lt;a href=&quot;https://guides.rubygems.org/llms.txt&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llms.txt&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://guides.rubygems.org/llms-full.txt&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llms-full.txt&lt;/code&gt;&lt;/a&gt; (&lt;a href=&quot;https://github.com/rubygems/guides/pull/525&quot;&gt;rubygems/guides#525&lt;/a&gt;). &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llms.txt&lt;/code&gt; lists every guide with a one-line description in about 10 KB, so an agent can fetch it once and jump straight to the page it needs. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llms-full.txt&lt;/code&gt; concatenates the full text of all guides into a single document of about 460 KB, roughly 120,000 tokens. That is most of a context window on many models, so it suits a tool that wants the whole corpus in one pass rather than an agent answering a single question.&lt;/p&gt;

&lt;p&gt;Neither file is written by hand. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llms.txt&lt;/code&gt; is generated from the same sidebar data that builds the site navigation, so a guide that shows up in the menu shows up in the index, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llms-full.txt&lt;/code&gt; is assembled by a Jekyll plugin at build time. Neither can quietly fall behind the guides themselves.&lt;/p&gt;

&lt;p&gt;The third serves raw Markdown for every page (&lt;a href=&quot;https://github.com/rubygems/guides/pull/524&quot;&gt;rubygems/guides#524&lt;/a&gt;). Append &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.md&lt;/code&gt; to any guide URL, such as &lt;a href=&quot;https://guides.rubygems.org/what-is-a-gem.md&quot;&gt;what-is-a-gem.md&lt;/a&gt;, and you get the rendered Markdown source with no navigation or markup. That cuts page size to between a half and an eighth of the HTML. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;what-is-a-gem&lt;/code&gt; is 26.7 KB as HTML and 3.3 KB as Markdown. Each HTML page also links its Markdown twin via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rel=&quot;alternate&quot; type=&quot;text/markdown&quot;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To try it, hand your agent the URL &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://guides.rubygems.org/llms.txt&lt;/code&gt; and ask a RubyGems question. One fetch gives it a table of contents. Every page it reads afterward fills the context window with the answer rather than with navigation and tags, so the same budget covers several times more material.&lt;/p&gt;

&lt;h3 id=&quot;new-formats-need-fresh-content&quot;&gt;New formats need fresh content&lt;/h3&gt;

&lt;p&gt;A machine readable feed is only as useful as the writing behind it. Serving an agent guidance that still mentioned freenode IRC and Ruby 1.8 path layouts would defeat the purpose, so the content was overhauled alongside the formats. The guides are reorganized around tasks instead of tools, into four sections named Getting Started, Guides, Concepts, and Reference. Full-text search is powered by Pagefind, so open any page, press Cmd+K or Ctrl+K, and search the whole site without leaving where you are.&lt;/p&gt;

&lt;p&gt;The new Concepts section explains how the system works, from &lt;a href=&quot;https://guides.rubygems.org/dependency-resolution/&quot;&gt;dependency resolution&lt;/a&gt; to platforms and native gems. Reference now documents &lt;a href=&quot;https://guides.rubygems.org/configuration/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gemrc&lt;/code&gt; configuration&lt;/a&gt; and environment variables for the first time, and absorbs the Bundler man pages. The &lt;a href=&quot;https://guides.rubygems.org/security/&quot;&gt;security guide&lt;/a&gt; was rewritten around MFA, Trusted Publishing, lockfile checksums, and &lt;a href=&quot;/2026/06/03/cooldown-let-new-gems-be-vetted.html&quot;&gt;cooldown&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;None of this is a one-off. Project DREAM (Driving Ruby’s Evolution to AI Maturity), which Ruby Central set out in &lt;a href=&quot;https://rubycentral.org/news/a-new-chapter-for-ruby-central/&quot;&gt;A New Chapter for Ruby Central&lt;/a&gt;, calls for extending RubyGems and the infrastructure around it to fit the patterns now emerging around AI. Documentation an agent can consume is part of that. Both audiences want the same things from a guide, which are clear structure, current facts, and a page you can reach without wading through anything else.&lt;/p&gt;

&lt;p&gt;This is not a finished piece of work. What counts as machine readable keeps moving, and the conventions that matter a year from now may not be the ones we implemented this week. We will keep watching what actually helps and adapting the guides to it. There is more coming.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>4.0.18 Released</title>
   <link href="https://blog.rubygems.org/2026/08/05/4.0.18-released.html"/>
   <updated>2026-08-05T00:00:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/08/05/4.0.18-released</id>
   <author><name>Hiroshi SHIBATA</name></author>
   <content type="html">&lt;p&gt;RubyGems 4.0.18 includes enhancements, bug fixes and documentation and Bundler 4.0.18 includes enhancements, bug fixes, security and documentation.&lt;/p&gt;

&lt;p&gt;To update to the latest RubyGems you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem update --system [--pre]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To update to the latest Bundler you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem install bundler [--pre]
bundle update --bundler=4.0.18
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;rubygems-release-notes&quot;&gt;RubyGems Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Check the resolved parent directory before extracting old format gems. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9755&quot;&gt;#9755&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Installs bundler 4.0.18 as a default gem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bug-fixes&quot;&gt;Bug fixes:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Call Kernel.format explicitly in Gem::Deprecate wrapper. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9714&quot;&gt;#9714&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;documentation&quot;&gt;Documentation:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Point bundler.io URLs at guides.rubygems.org. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9737&quot;&gt;#9737&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;bundler-release-notes&quot;&gt;Bundler Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements-1&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Don’t mask install errors when no Gemfile can be located. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9757&quot;&gt;#9757&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Warn when duplicate source declarations conflict on cooldown. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9736&quot;&gt;#9736&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Redact URI userinfo from settings names in Bundler User-Agent. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9716&quot;&gt;#9716&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Validate gem name before building compact index cache paths. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9717&quot;&gt;#9717&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bug-fixes-1&quot;&gt;Bug fixes:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Fail &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle check&lt;/code&gt; when frozen mode needs lockfile changes. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9715&quot;&gt;#9715&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Skip empty checksum values in compact index metadata. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9713&quot;&gt;#9713&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;security&quot;&gt;Security:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Add –cooldown flag to bundle lock and bundle cache. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9725&quot;&gt;#9725&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;documentation-1&quot;&gt;Documentation:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Point bundler.io URLs at guides.rubygems.org. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9737&quot;&gt;#9737&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Document Bundler checksum behavior for default gems. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9735&quot;&gt;#9735&lt;/a&gt; by p-linnane&lt;/li&gt;
  &lt;li&gt;List missing subcommands in bundle(1) UTILITIES section. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9721&quot;&gt;#9721&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Document pessimistic operator and eval_gemfile in gemfile(5). Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9719&quot;&gt;#9719&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;manual-installation&quot;&gt;Manual Installation&lt;/h2&gt;

&lt;p&gt;To install RubyGems by hand see the &lt;a href=&quot;https://rubygems.org/pages/download&quot;&gt;Download RubyGems&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;SHA256 Checksums:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;rubygems-4.0.18.tgz&lt;br /&gt;
8ff8738ecbf147d1bd2eff1ca13ea432c45e9bd9489f46a74fb99e7117ed890c&lt;/li&gt;
  &lt;li&gt;rubygems-4.0.18.zip&lt;br /&gt;
637f11a5b337e85ec746d84b76eee4e27e1697c947c9128492e1c5d6359a18c4&lt;/li&gt;
  &lt;li&gt;rubygems-update-4.0.18.gem&lt;br /&gt;
a6a8653069b81b7977d4d341b3ba9f0212f14aa9756f0143dca2dcc3e793db97&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Security advisory: Possible leak of legacy API keys via improper cache configuration</title>
   <link href="https://blog.rubygems.org/2026/07/22/security-advisory-legacy-api-key-leak.html"/>
   <updated>2026-07-22T21:02:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/07/22/security-advisory-legacy-api-key-leak</id>
   <author><name>Colby Swandale</name></author>
   <content type="html">&lt;p&gt;A CDN caching bug on RubyGems.org could hand one account’s API key to another person for up to an hour. If you signed in to RubyGems.org with a gem client older than v3.2.0, your key could have been exposed (the technical details are below). Currently, 18% of sign-ins through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem signin&lt;/code&gt; come from an affected version, and for the first several years of this bug, before we changed the client’s sign-in path in December 2020, it was every gem client.&lt;/p&gt;

&lt;p&gt;We’ve reviewed the access logs we keep and found no sign of a legacy key being used maliciously, and no user or support report has suggested otherwise. Those logs only cover a recent window, though, a small slice of the years this bug is estimated to have been present. Rather than lean on log analysis to rule out any potential abuse, we’ve revoked every RubyGems.org legacy key, and we’re asking owners to check their own gems.&lt;/p&gt;

&lt;p&gt;Your already-published gems were never at risk: existing releases cannot be rewritten, and installing gems was never affected. What was at risk is the key itself. Anyone holding a leaked key could act as that account: publish a new gem version, yank versions, add themselves as an owner.&lt;/p&gt;

&lt;p&gt;If you had MFA enabled for API requests, your key could still have leaked, but MFA blocks a leaked key from pushing, yanking, or changing owners.&lt;/p&gt;

&lt;h2 id=&quot;what-account-holders-should-check&quot;&gt;What account holders should check&lt;/h2&gt;

&lt;p&gt;Existing releases cannot be rewritten, so if you’re an account owner, what you are checking for is anything added or removed under your name. On each of your gems, look for versions you did not publish (especially one higher than your latest), unexpected yanks, unfamiliar owners or maintainers, trusted publishers you did not configure, and webhooks you do not recognise.&lt;/p&gt;

&lt;p&gt;We’re notifying users whose account held a legacy API key at any point, since those are the accounts this bug could have exposed, so please keep an eye on your inbox. You can immediately review your account’s &lt;a href=&quot;https://rubygems.org/profile/api_keys&quot;&gt;API Key history&lt;/a&gt; through your profile page.&lt;/p&gt;

&lt;h2 id=&quot;what-is-a-rubygemsorg-legacy-api-key&quot;&gt;What is a RubyGems.org Legacy API Key&lt;/h2&gt;

&lt;p&gt;A Legacy API key is a single credential that carries every gem-management permission at once. It isn’t tied to a single gem, so those permissions apply across every gem you own, and it has no expiry, so it stays valid until you delete it.&lt;/p&gt;

&lt;p&gt;In practice that means the key can do many operations the API exposes for publishing and maintaining your gems: push a new version, yank an existing one, add or remove owners, change webhooks, and configure trusted publishers. What it can’t do is act as a full account login. No API key can change your password or email, alter your MFA settings, or delete your account.&lt;/p&gt;

&lt;p&gt;The word “legacy” undersells how ordinary these keys were. When this endpoint was built, and for years afterward, this was simply the API key: the only kind RubyGems.org issued, and the only way the gem CLI could sign you in. Scoped keys arrived in RubyGems v3.2.0 in December 2020, and it’s at that point the older keys became “legacy”. So for most of the roughly nine years this bug existed, the affected credential wasn’t a deprecated relic that a few stragglers still used. It was the standard way everyone authenticated.&lt;/p&gt;

&lt;h2 id=&quot;who-is-affected&quot;&gt;Who is affected&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Users of the rubygems client older than v3.2.0, which signs in by calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET /api/v1/api_key&lt;/code&gt;. Notably, this includes the vendored rubygems with current macOS (Tahoe), version &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3.0.3.1&lt;/code&gt; at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/bin/gem&lt;/code&gt;, so the affected client is a standard system tool, not an edge case.&lt;/li&gt;
  &lt;li&gt;Recipients of a leaked key, who may be entirely uninvolved account holders. A cached hit wrote another account’s key into their local credentials file, and from that point they acted as the other account until they signed in again.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;technical-detail&quot;&gt;Technical detail&lt;/h2&gt;

&lt;p&gt;Under a specific interaction between the response compression and cache headers, our CDN cached the successful response and served the same freshly created key to subsequent callers on the same edge node (POPs) for up to an hour, without re-checking their credentials.&lt;/p&gt;

&lt;p&gt;The result was that one account’s API key could be handed to another party, with no attacker involved. Once one user’s sign-in response was cached at a Fastly edge node, the next user signing in through that same node within the hour received the earlier user’s key instead of a fresh one of their own. And because cache hits were served at the edge without contacting the origin, an unauthenticated party could also poll the endpoint to harvest whatever key happened to be cached.&lt;/p&gt;

&lt;p&gt;The chain is as follows:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET /api/v1/api_key&lt;/code&gt; authenticates with HTTP Basic and creates a new legacy key, returning it in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;200&lt;/code&gt; body.&lt;/li&gt;
  &lt;li&gt;The Ruby client sends &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Accept-Encoding: gzip&lt;/code&gt; by default (via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Net::HTTP&lt;/code&gt;). &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rack::Deflater&lt;/code&gt; replaces the response body with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GzipStream&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rack::ETag&lt;/code&gt; can’t read the gzipped body, so it falls back to a bare &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cache-Control: no-cache&lt;/code&gt;, with no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;private&lt;/code&gt; and no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Set-Cookie&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;With only a bare &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;no-cache&lt;/code&gt; and no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vary: Authorization&lt;/code&gt;, Fastly cached the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;200&lt;/code&gt; for up to an hour under a shared cache key for the single CDN node that processed that request. Every cache hit during that window returned the same key, served at the edge without re-authenticating the caller.&lt;/li&gt;
  &lt;li&gt;A successful response here is itself the API key.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A detail worth calling out, because it explains why casual testing missed this: the bug is conditional on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Accept-Encoding: gzip&lt;/code&gt;. A plain &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt; request, which sends no such header, received a correct-looking &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cache-Control: private, must-revalidate&lt;/code&gt; response and did not reproduce the issue. The vulnerable path was the one the real Ruby client exercises by default.&lt;/p&gt;

&lt;p&gt;The application-side trigger (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rack::Deflater&lt;/code&gt;) was introduced on 10 October 2016 (commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;03d89c0&lt;/code&gt;). The date the response first became edge-cacheable cannot be established from the repository, so the conservative assumption is that the endpoint was exploitable for most of the roughly nine years since.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We have assigned this incident the following CVSS score:&lt;/strong&gt;&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;CVSS Version&lt;/th&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;4.0&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Base Score (CVSS-B)&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;7.3 (High)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Environmental Score (CVSS-BE)&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;7.2 (High)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Overall Score&lt;/strong&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;7.2 (High)&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;Macro Vector&lt;/td&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;111100&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Vector String:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:L/VI:H/VA:H/SC:L/SI:H/SA:H/CR:L/IR:H/AR:H/MAV:N/MAC:L/MAT:P/MPR:N/MUI:P/MVC:L/MVI:H/MVA:H/MSC:L/MSI:H/MSA:H&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;impact-and-its-limits&quot;&gt;Impact and its limits&lt;/h2&gt;

&lt;p&gt;Adding an owner and registering a trusted publisher persists even after the key itself is revoked, which is why key revocation alone is necessary but not sufficient, and why we asked owners to review their ownership and trusted-publisher settings.&lt;/p&gt;

&lt;p&gt;There are firm limits on what was possible:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Existing gem releases cannot be altered by users. Any existing name, version, and platform is immutable; pushing an already published version is rejected with HTTP 409 “Repushing of gem versions is not allowed”. A yanked version number cannot be reused either.&lt;/li&gt;
  &lt;li&gt;What “clobbering” actually means here is shipping a new, higher version that supersedes the current one as the default install, yanking versions, or (after yanking all versions) reclaiming a name. A new platform variant of an existing version number is a distinct, allowed artifact rather than an overwrite. None of this rewrites an already-published release.&lt;/li&gt;
  &lt;li&gt;MFA helps when enabled on API requests. A leaked key is neutralised for push, yank, owner changes, and trusted-publisher changes when the account has enabled it for API requests (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ui_and_api&lt;/code&gt;), which forces multifactor authentication on those actions. Accounts set to disabled, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ui_and_gem_signin&lt;/code&gt;, get no such protection against a leaked key.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;when-the-vulnerable-client-path-was-retired&quot;&gt;When the vulnerable client path was retired&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem signin&lt;/code&gt; flow stopped calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET /api/v1/api_key&lt;/code&gt; in RubyGems v3.2.0, released 10 December 2020, which switched sign-in to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST /api/v1/api_key&lt;/code&gt; as part of the &lt;a href=&quot;https://github.com/ruby/rubygems/pull/3840&quot;&gt;introduction of scoped API keys&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That client change did not remove the risk, because the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt; endpoint was deliberately kept on the server so that actively maintained clients would keep working. It continued to mint new API keys for every caller until the fix below. In other words, the client version determined only whether the modern &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem&lt;/code&gt; reached the endpoint; the endpoint itself remained live and cacheable for everyone, including direct API callers, for the whole period.&lt;/p&gt;

&lt;h2 id=&quot;why-we-didnt-detect-this-before&quot;&gt;Why we didn’t detect this before&lt;/h2&gt;

&lt;p&gt;Attribution of any misuse is difficult by design of the platform, and we want to be plain about that rather than reassuring:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Every action taken with a key is recorded under the legitimate key-holder. The pusher, the event actor, the notification emails, and the rate-limit bucket all read as the rightful owner.&lt;/li&gt;
  &lt;li&gt;The only signals that distinguish a different caller are the source IP address and user-agent. There was no notification on key use (only on key creation), and no new-IP or velocity alerting on API keys.&lt;/li&gt;
  &lt;li&gt;As noted above, the flaw only manifested for gzip-compressed requests, so header inspection with ordinary tools did not surface it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The worst-case exposure dates back to 2016 and our log history is limited. As a result, most of that window cannot be reconstructed. This is why we treated revocation as the remedy and any log review as best-effort corroboration only.&lt;/p&gt;

&lt;h2 id=&quot;the-fix&quot;&gt;The fix&lt;/h2&gt;

&lt;p&gt;Deployed in commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;d3d11c0&lt;/code&gt; (9 July 2026):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The authentication response now sets &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cache-Control: private, no-store&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Surrogate-Control: max-age=0&lt;/code&gt;, and appends &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Authorization&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vary&lt;/code&gt; on the API key response and on the other authenticated API endpoints. The sign-in response can no longer be stored in a shared cache, and any cache that does store a response now varies on the credential.&lt;/li&gt;
  &lt;li&gt;We purged the affected objects from Fastly before revoking keys, so re-issued keys could not be re-poisoned.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;remediation-and-what-breaks&quot;&gt;Remediation and what breaks&lt;/h2&gt;

&lt;p&gt;We’ve revoked all legacy API keys. No other keys were affected. Scoped keys created through the RubyGems.org UI and the RubyGems CLI were never exposed by this bug, which only affected the legacy sign-in method, not the way scoped keys are created. Short-lived OIDC and trusted-publisher keys were also left alone, since they come from a separate token exchange, expire on their own within minutes, and can’t leak through this path.&lt;/p&gt;

&lt;p&gt;Because only legacy keys were revoked, the breakage is limited and predictable:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem install&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle install&lt;/code&gt; are anonymous and keep working.&lt;/li&gt;
  &lt;li&gt;The next &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem push&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem yank&lt;/code&gt;, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem owner&lt;/code&gt; using an expired legacy key will return an HTTP 401 response. To recover, create a new API key at &lt;a href=&quot;https://rubygems.org/profile/api_keys&quot;&gt;https://rubygems.org/profile/api_keys&lt;/a&gt; and load it into your local RubyGems configuration by following the &lt;a href=&quot;https://guides.rubygems.org/api-key-scopes/&quot;&gt;API key guide&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;For CI or automation using legacy keys, the next gem push will return an HTTP 401 response until you replace the stored key (for example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RUBYGEMS_API_KEY&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GEM_HOST_API_KEY&lt;/code&gt;) with a newly created one. CI that only installs gems is unaffected, and CI already using trusted publishing (OIDC) keeps working, since those keys weren’t revoked and are re-minted on each run.&lt;/li&gt;
  &lt;li&gt;If you moved off legacy keys to scoped keys, nothing was revoked and no further action is required.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ve also retired the old sign-in endpoint (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET /api/v1/api_key&lt;/code&gt;), so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem signin&lt;/code&gt; on RubyGems clients older than v3.2.0 no longer works. Creating a key on the website and loading it as above works on any client version, and replacing your stored key this way also clears any key you may have been unknowingly holding for another account.&lt;/p&gt;

&lt;p&gt;We recommend scoped keys over full-access keys, MFA enabled for API access, and trusted publishing over long-lived keys in CI.&lt;/p&gt;

&lt;h2 id=&quot;timeline&quot;&gt;Timeline&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;10 October 2016: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rack::Deflater&lt;/code&gt; added, introducing the application-side trigger (commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;03d89c0&lt;/code&gt;).&lt;/li&gt;
  &lt;li&gt;10 December 2020: RubyGems v3.2.0 released; the modern &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem signin&lt;/code&gt; stops calling the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt; endpoint, though the endpoint remains for older clients.&lt;/li&gt;
  &lt;li&gt;6 July 2026: reported to RubyGems.org by Luke Marshall&lt;/li&gt;
  &lt;li&gt;9 July 2026: root-cause fix deployed (commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;d3d11c0&lt;/code&gt;), Fastly purged&lt;/li&gt;
  &lt;li&gt;23 July 2026: Legacy API keys revoked, affected users notified &amp;amp; public disclosure published&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;credit&quot;&gt;Credit&lt;/h2&gt;

&lt;p&gt;Thanks to Luke Marshall from &lt;a href=&quot;https://trufflesecurity.com/blog/rubygems-cache-vulnerability&quot;&gt;Truffle Security&lt;/a&gt; for the responsible report and for working with us through remediation. This security report has been published as &lt;a href=&quot;https://github.com/rubygems/rubygems.org/security/advisories/GHSA-9j48-x3c3-mrp2&quot;&gt;GHSA-9j48-x3c3-mrp2&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;our-commitment-to-security&quot;&gt;Our commitment to security&lt;/h2&gt;

&lt;p&gt;I lead the team that maintains RubyGems.org and my name is on Bundler, rubygems &amp;amp; RubyGems.org going back almost a decade. When the report came in, the first thing I felt wasn’t so much about the bug itself. It was the question of how it sat there, in the open, for the better part of a decade, and we never caught it ourselves. We found this because someone told us, not because we saw it, and I want to be honest about that.&lt;/p&gt;

&lt;p&gt;Beyond the actions we’ve taken today, we’re looking at expanding the two-factor authentication requirement across the platform in 2026, so a single leaked key is worth much less on its own. If you haven’t already, please turn it on today and set it to apply to both the &lt;a href=&quot;https://guides.rubygems.org/setting-up-multifactor-authentication/&quot;&gt;UI and API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;None of this makes RubyGems.org 100% safe, and I won’t pretend it does. Each of these fixes a specific weakness this incident exposed, and we’ll keep working on the rest. RubyGems.org is infrastructure that nearly every Ruby developer depends on, and keeping it secure is the core of what our team is here to do.&lt;/p&gt;

&lt;p&gt;Colby Swandale, RubyGems.org Technical Lead&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>4.0.17 Released</title>
   <link href="https://blog.rubygems.org/2026/07/22/4.0.17-released.html"/>
   <updated>2026-07-22T00:00:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/07/22/4.0.17-released</id>
   <author><name>Hiroshi SHIBATA</name></author>
   <content type="html">&lt;p&gt;RubyGems 4.0.17 includes enhancements and bug fixes and Bundler 4.0.17 includes enhancements, bug fixes and documentation.&lt;/p&gt;

&lt;p&gt;To update to the latest RubyGems you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem update --system [--pre]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To update to the latest Bundler you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem install bundler [--pre]
bundle update --bundler=4.0.17
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;rubygems-release-notes&quot;&gt;RubyGems Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Validate spec name before writing to the spec cache. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9690&quot;&gt;#9690&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Installs bundler 4.0.17 as a default gem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bug-fixes&quot;&gt;Bug fixes:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Unquote Gem.ruby when spawning it as a separate argv element. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9695&quot;&gt;#9695&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Escape glob metacharacters in install paths when globbing. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9687&quot;&gt;#9687&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Preserve Windows editor paths in gem open and bundle open. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9694&quot;&gt;#9694&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Preserve Windows paths in MAKE and rake environment variables. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9693&quot;&gt;#9693&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Fix &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle&lt;/code&gt; binstub broken by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem update --system&lt;/code&gt; on Homebrew ruby. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9688&quot;&gt;#9688&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;bundler-release-notes&quot;&gt;Bundler Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements-1&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Open compact index cache in binary mode when appending. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9679&quot;&gt;#9679&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bug-fixes-1&quot;&gt;Bug fixes:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Unquote Gem.ruby when spawning it as a separate argv element. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9695&quot;&gt;#9695&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Escape glob metacharacters in install paths when globbing. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9687&quot;&gt;#9687&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Avoid space-containing absolute path in RUBYOPT. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9696&quot;&gt;#9696&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Preserve the locked Bundler checksum when the gem isn’t cached. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9658&quot;&gt;#9658&lt;/a&gt; by rwstauner&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;documentation&quot;&gt;Documentation:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Point Bundler gemspec metadata at the moved docs. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9648&quot;&gt;#9648&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;manual-installation&quot;&gt;Manual Installation&lt;/h2&gt;

&lt;p&gt;To install RubyGems by hand see the &lt;a href=&quot;https://rubygems.org/pages/download&quot;&gt;Download RubyGems&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;SHA256 Checksums:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;rubygems-4.0.17.tgz&lt;br /&gt;
5bbb245b7e7c1a01b1ef7fa95c35517ebf3be77815cbe3e63c97c3067b9a0d13&lt;/li&gt;
  &lt;li&gt;rubygems-4.0.17.zip&lt;br /&gt;
4f3cf8d8d2250be984f7ee4516b3138d82054db7ee759ec6fc6839f4557b464b&lt;/li&gt;
  &lt;li&gt;rubygems-update-4.0.17.gem&lt;br /&gt;
a3f458ae8fcf607602bb9ae111ac9a57036914c2e6bce7736418df504ec4e455&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>4.0.16 Released</title>
   <link href="https://blog.rubygems.org/2026/07/10/4.0.16-released.html"/>
   <updated>2026-07-10T00:00:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/07/10/4.0.16-released</id>
   <author><name>Hiroshi SHIBATA</name></author>
   <content type="html">&lt;p&gt;RubyGems 4.0.16 includes enhancements and bug fixes and Bundler 4.0.16 includes enhancements, bug fixes and documentation.&lt;/p&gt;

&lt;p&gt;To update to the latest RubyGems you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem update --system [--pre]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To update to the latest Bundler you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem install bundler [--pre]
bundle update --bundler=4.0.16
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;rubygems-release-notes&quot;&gt;RubyGems Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Installs bundler 4.0.16 as a default gem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bug-fixes&quot;&gt;Bug fixes:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Skip the make job server when using BSD make. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9676&quot;&gt;#9676&lt;/a&gt; by flavorjones&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;bundler-release-notes&quot;&gt;Bundler Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements-1&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Bundler: Fix Bundler::Fetcher for PQC support, adding integration connection tests. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9637&quot;&gt;#9637&lt;/a&gt; by junaruga&lt;/li&gt;
  &lt;li&gt;Reuse RubyGems’ vendored tsort in Bundler. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9647&quot;&gt;#9647&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bug-fixes-1&quot;&gt;Bug fixes:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Initialize the new gem’s git repo without a subshell. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9670&quot;&gt;#9670&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Preserve CRLF lockfile line endings on Windows. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9669&quot;&gt;#9669&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Fix the gemspec error snippet on Windows drive-letter paths. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9668&quot;&gt;#9668&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;documentation&quot;&gt;Documentation:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Point Bundler gemspec metadata at the moved docs. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9648&quot;&gt;#9648&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;manual-installation&quot;&gt;Manual Installation&lt;/h2&gt;

&lt;p&gt;To install RubyGems by hand see the &lt;a href=&quot;https://rubygems.org/pages/download&quot;&gt;Download RubyGems&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;SHA256 Checksums:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;rubygems-4.0.16.tgz&lt;br /&gt;
ea9c669526af82874f8f33f69bea1b6ddd99283756e598227a9a890035a5a06a&lt;/li&gt;
  &lt;li&gt;rubygems-4.0.16.zip&lt;br /&gt;
1c76924eddda3b1fe2922a2a9022eeee51706d31b5c0ed9e00c777c399e23e71&lt;/li&gt;
  &lt;li&gt;rubygems-update-4.0.16.gem&lt;br /&gt;
0475b0b254d46e5eeec1bfc2ef17fa0eaaf17ae561806b74652d1bffbef6ff8d&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>4.0.15 Released</title>
   <link href="https://blog.rubygems.org/2026/06/24/4.0.15-released.html"/>
   <updated>2026-06-24T00:00:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/06/24/4.0.15-released</id>
   <author><name>Hiroshi SHIBATA</name></author>
   <content type="html">&lt;p&gt;RubyGems 4.0.15 includes enhancements and bug fixes and Bundler 4.0.15 includes enhancements and bug fixes.&lt;/p&gt;

&lt;p&gt;To update to the latest RubyGems you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem update --system [--pre]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To update to the latest Bundler you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem install bundler [--pre]
bundle update --bundler=4.0.15
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;rubygems-release-notes&quot;&gt;RubyGems Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Rubygems: Fix Gem::Request for PQC support, adding integration connection tests. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9615&quot;&gt;#9615&lt;/a&gt; by junaruga&lt;/li&gt;
  &lt;li&gt;Reduce peak memory usage of full index loading and bundle install. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9618&quot;&gt;#9618&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Installs bundler 4.0.15 as a default gem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bug-fixes&quot;&gt;Bug fixes:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Forward security policy to old-format gems. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9611&quot;&gt;#9611&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;bundler-release-notes&quot;&gt;Bundler Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements-1&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Resolve Git LFS files in git sources from the real remote. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9632&quot;&gt;#9632&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Suggest access issues, not only yanking, for missing locked gems. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9631&quot;&gt;#9631&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Implement a make jobserver (continuation of #9210). Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9625&quot;&gt;#9625&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Reduce peak memory usage of full index loading and bundle install. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9618&quot;&gt;#9618&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Bump up to rb-sys 0.9.128. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9569&quot;&gt;#9569&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bug-fixes-1&quot;&gt;Bug fixes:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Skip the make jobserver on Windows. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9630&quot;&gt;#9630&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Don’t require source plugins to be installed to parse a lockfile: 4.0.x. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9621&quot;&gt;#9621&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Exempt lockfile versions from cooldown on every resolution path. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9619&quot;&gt;#9619&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bundler.settings[:ssl_ca_cert]&lt;/code&gt; to download gems. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9610&quot;&gt;#9610&lt;/a&gt; by junaruga&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;manual-installation&quot;&gt;Manual Installation&lt;/h2&gt;

&lt;p&gt;To install RubyGems by hand see the &lt;a href=&quot;https://rubygems.org/pages/download&quot;&gt;Download RubyGems&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;SHA256 Checksums:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;rubygems-4.0.15.tgz&lt;br /&gt;
ec63459a0746d6e33804c0d6cbbcd1bcc6359f44fcada267b0f489cc84083687&lt;/li&gt;
  &lt;li&gt;rubygems-4.0.15.zip&lt;br /&gt;
54e30f36e5dbf193e1abbb1d6f995a83d3f1bcab0ff4cfe21064c8a3cb9554ed&lt;/li&gt;
  &lt;li&gt;rubygems-update-4.0.15.gem&lt;br /&gt;
bb22f30d9172f4ecd646c2bc8de341a820814401bcada5d7c5c541bd63b8f427&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>4.0.14 Released</title>
   <link href="https://blog.rubygems.org/2026/06/10/4.0.14-released.html"/>
   <updated>2026-06-10T00:00:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/06/10/4.0.14-released</id>
   <author><name>Hiroshi SHIBATA</name></author>
   <content type="html">&lt;p&gt;RubyGems 4.0.14 includes enhancements and Bundler 4.0.14 includes bug fixes.&lt;/p&gt;

&lt;p&gt;To update to the latest RubyGems you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem update --system [--pre]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To update to the latest Bundler you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem install bundler [--pre]
bundle update --bundler=4.0.14
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;rubygems-release-notes&quot;&gt;RubyGems Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Add executables and bindir validation to the gem installer. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9595&quot;&gt;#9595&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Strip C1 control characters from displayed gem text. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9597&quot;&gt;#9597&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Installs bundler 4.0.14 as a default gem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;bundler-release-notes&quot;&gt;Bundler Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;bug-fixes&quot;&gt;Bug fixes:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Preserve per-source cooldown when converging sources from the lockfile. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9601&quot;&gt;#9601&lt;/a&gt; by bryanwoods&lt;/li&gt;
  &lt;li&gt;Don’t exclude the locked version from cooldown during bundle update. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9599&quot;&gt;#9599&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;manual-installation&quot;&gt;Manual Installation&lt;/h2&gt;

&lt;p&gt;To install RubyGems by hand see the &lt;a href=&quot;https://rubygems.org/pages/download&quot;&gt;Download RubyGems&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;SHA256 Checksums:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;rubygems-4.0.14.tgz&lt;br /&gt;
7cb03059c028d073dd1efab322dddd6fe9e1a5976e2d35a1806066e069588812&lt;/li&gt;
  &lt;li&gt;rubygems-4.0.14.zip&lt;br /&gt;
8d93b7b8371309b9e4fe4c8d4da5e8f1e41d3ec5dd60af57b953793a039d9ae5&lt;/li&gt;
  &lt;li&gt;rubygems-update-4.0.14.gem&lt;br /&gt;
11ad1d808025f191c9cdde38bfb96aec01c7b75746870fe396a3334bdc29d050&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Cool down before you install: give new gems a few days to be vetted</title>
   <link href="https://blog.rubygems.org/2026/06/03/cooldown-let-new-gems-be-vetted.html"/>
   <updated>2026-06-03T00:00:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/06/03/cooldown-let-new-gems-be-vetted</id>
   <author><name>Hiroshi SHIBATA</name></author>
   <content type="html">&lt;p&gt;Most supply-chain attacks against RubyGems exploit a narrow window: an account is compromised, a malicious version ships, and any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle install&lt;/code&gt; in the minutes that follow resolves straight to it. &lt;strong&gt;Bundler 4.0.13&lt;/strong&gt; introduces &lt;strong&gt;cooldown&lt;/strong&gt;, a time-based filter that refuses to resolve to a version until it has been public for at least &lt;em&gt;N&lt;/em&gt; days. Releases too new to have been scrutinized are passed over in favor of ones that have aged past the window.&lt;/p&gt;

&lt;p&gt;The feature was &lt;a href=&quot;https://github.com/ruby/rubygems/discussions/9113&quot;&gt;designed in the open&lt;/a&gt;, drawing on &lt;a href=&quot;https://dev.to/hsbt/should-rubygemsbundler-have-a-cooldown-feature-40cp&quot;&gt;how other ecosystems approach the same problem&lt;/a&gt;. It is opt-in, and complements rather than replaces existing defenses like mandatory 2FA and trusted publishing.&lt;/p&gt;

&lt;p&gt;Cooldown reads the per-version &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;created_at&lt;/code&gt; timestamp that rubygems.org’s v2 compact index now serves. A version whose source does not expose &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;created_at&lt;/code&gt;, such as older gem servers, historical entries from before the v2 cutover, or private registries still on the v1 format, is treated as outside the window and stays resolvable. Cooldown never blocks resolution silently; it only holds back versions it can prove are too new.&lt;/p&gt;

&lt;h3 id=&quot;getting-started&quot;&gt;Getting started&lt;/h3&gt;

&lt;p&gt;Cooldown ships in &lt;a href=&quot;/2026/06/03/4.0.13-released.html&quot;&gt;Bundler 4.0.13&lt;/a&gt;. If you are on an earlier release, update Bundler in place and pin the same version in your lockfile so the whole team moves together:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;gem update &lt;span class=&quot;nt&quot;&gt;--system&lt;/span&gt;          &lt;span class=&quot;c&quot;&gt;# or: gem install bundler -v 4.0.13&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;bundle update &lt;span class=&quot;nt&quot;&gt;--bundler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;4.0.13
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then declare a small cooldown on your source in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt;. This is the right setup for most teams: it is committed alongside your code, so every developer and CI run enforce the same window with no extra setup.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://rubygems.org&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;cooldown: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;rails&quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;puma&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Cooldown takes effect during resolution. Run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle install&lt;/code&gt; when there is no lockfile yet, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle update&lt;/code&gt; to re-resolve against it once a lockfile exists; an existing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gemfile.lock&lt;/code&gt; is always honored as-is, so adding a cooldown never disturbs versions you have already locked. Cooldown is unset by default, so a project without it keeps resolving to the newest versions.&lt;/p&gt;

&lt;p&gt;That is all most projects need. The rest of this post covers the finer-grained controls.&lt;/p&gt;

&lt;h3 id=&quot;other-ways-to-set-it&quot;&gt;Other ways to set it&lt;/h3&gt;

&lt;p&gt;Beyond the per-source keyword, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cooldown&lt;/code&gt; setting applies one value across every source, scoped per-project, globally, or through the environment:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;bundle config &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;cooldown 7          &lt;span class=&quot;c&quot;&gt;# stored in .bundle/config for this project&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;bundle config &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; cooldown 7 &lt;span class=&quot;c&quot;&gt;# applies to every project for this user&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BUNDLE_COOLDOWN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;7 bundle &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;      &lt;span class=&quot;c&quot;&gt;# no lockfile yet, e.g. a fresh CI checkout&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BUNDLE_COOLDOWN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;7 bundle update       &lt;span class=&quot;c&quot;&gt;# re-resolve when a lockfile already exists&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For a one-off run, pass &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--cooldown&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;install&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add&lt;/code&gt;, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;outdated&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--cooldown&lt;/span&gt; 7
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;bundle update &lt;span class=&quot;nt&quot;&gt;--cooldown&lt;/span&gt; 7
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;bundle add rails &lt;span class=&quot;nt&quot;&gt;--cooldown&lt;/span&gt; 7
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;bundle outdated &lt;span class=&quot;nt&quot;&gt;--cooldown&lt;/span&gt; 7
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When more than one of these is present, they resolve in a fixed order of precedence: &lt;strong&gt;command-line flag &amp;gt; configuration setting &amp;gt; per-source &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cooldown:&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt;&lt;/strong&gt;. A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--cooldown&lt;/code&gt; flag overrides the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cooldown&lt;/code&gt; setting (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle config&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BUNDLE_COOLDOWN&lt;/code&gt;), which in turn overrides a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cooldown:&lt;/code&gt; declared on a source. The cooldown value is always a &lt;strong&gt;non-negative integer number of days&lt;/strong&gt;; a string, float, negative number, or array is rejected with an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InvalidOption&lt;/code&gt; error.&lt;/p&gt;

&lt;h3 id=&quot;mixing-sources&quot;&gt;Mixing sources&lt;/h3&gt;

&lt;p&gt;Because the flag and the setting apply &lt;strong&gt;uniformly to every source&lt;/strong&gt;, the per-source keyword is what you reach for when policy differs by registry, for instance cooling down public gems while trusting an internal registry you operate:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://rubygems.org&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;cooldown: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://gems.internal.example.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;cooldown: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;internal-tool&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cooldown: 0&lt;/code&gt; on the private source keeps it permanently exempt while public gems still age. Note that a command-line &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--cooldown N&lt;/code&gt; overrides every source for that run, including the exempt one.&lt;/p&gt;

&lt;h3 id=&quot;the-escape-hatch&quot;&gt;The escape hatch&lt;/h3&gt;

&lt;p&gt;Passing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; disables cooldown for the run. It is the reliable way to reach the newest version on demand and to override a per-source or configured cooldown. This matters most when waiting is the wrong default: a fix lands for an actively exploited 0-day, or a vulnerability disclosure tells you to upgrade immediately. In those cases the freshest release is exactly the one you want, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--cooldown 0&lt;/code&gt; lets you take it without removing the policy for everyone else:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--cooldown&lt;/span&gt; 0
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BUNDLE_COOLDOWN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0 bundle update rails   &lt;span class=&quot;c&quot;&gt;# ignore any configured cooldown this time&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You will reach for this when every candidate version of a gem is still inside the window. Rather than fall back to a too-new release, Bundler stops, reports how many versions the cooldown excluded, and points you at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--cooldown 0&lt;/code&gt; to proceed.&lt;/p&gt;

&lt;h3 id=&quot;seeing-what-is-held-back&quot;&gt;Seeing what is held back&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle outdated&lt;/code&gt; is cooldown-aware. It annotates versions that are newer but still inside the window with the days left before they become resolvable, so “up to date” stays distinct from “deliberately waiting”:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;bundle outdated &lt;span class=&quot;nt&quot;&gt;--cooldown&lt;/span&gt; 7
&lt;span class=&quot;go&quot;&gt;Gem             Current   Latest                  Requested   Groups
aws-partitions  1.1251.0  1.1256.0 (cooldown 3d)  = 1.1251.0  default
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;one-layer-among-many&quot;&gt;One layer among many&lt;/h3&gt;

&lt;p&gt;Cooldown is most useful as one part of the wider security investment happening on rubygems.org. The registry now validates gem contents at push time and checks logins against Have I Been Pwned so that compromised passwords cannot be reused, work described in &lt;a href=&quot;/2026/04/09/protecting-rubygems-from-the-outside-in.html&quot;&gt;Protecting rubygems.org from the outside in&lt;/a&gt;. A dedicated team is running &lt;a href=&quot;/2026/04/29/scaling-rubys-defenses-with-ai.html&quot;&gt;AI-assisted vulnerability scanning against the most critical gems&lt;/a&gt;, backed by Alpha Omega and Anthropic, and the direction of all of this is tracked on a &lt;a href=&quot;/2026/04/15/rubygems-org-has-a-public-roadmap.html&quot;&gt;public roadmap&lt;/a&gt;. Trusted publishing and mandatory 2FA already raise the bar for who can push a release in the first place.&lt;/p&gt;

&lt;p&gt;Cooldown itself only works because rubygems.org now publishes the per-version &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;created_at&lt;/code&gt; timestamp through its &lt;a href=&quot;https://github.com/rubygems/rubygems.org/issues/6412&quot;&gt;v2 compact index&lt;/a&gt; (v2 is an internal format version, not a public API change), delivered through a careful dual-write migration and a flagged cutover with no disruption for clients. I’m grateful to the rubygems.org team for that groundwork. Cooldown is a thin client-side filter on top of it.&lt;/p&gt;

&lt;p&gt;Each of these defenses covers a different gap, and they compound. Resolving your dependencies against rubygems.org is what puts all of them to work on your behalf, which makes it the safest default for Ruby projects.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>4.0.13 Released</title>
   <link href="https://blog.rubygems.org/2026/06/03/4.0.13-released.html"/>
   <updated>2026-06-03T00:00:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/06/03/4.0.13-released</id>
   <author><name>Hiroshi SHIBATA</name></author>
   <content type="html">&lt;p&gt;RubyGems 4.0.13 includes enhancements and Bundler 4.0.13 includes enhancements, bug fixes and security.&lt;/p&gt;

&lt;p&gt;To update to the latest RubyGems you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem update --system [--pre]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To update to the latest Bundler you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem install bundler [--pre]
bundle update --bundler=4.0.13
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;rubygems-release-notes&quot;&gt;RubyGems Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Prevent extraction from escaping destination_dir via pre-existing symlinks. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9493&quot;&gt;#9493&lt;/a&gt; by thesmartshadow&lt;/li&gt;
  &lt;li&gt;Close stdin immediately when using popen2e. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9540&quot;&gt;#9540&lt;/a&gt; by rwstauner&lt;/li&gt;
  &lt;li&gt;Fallback to copy symlinks on Windows. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9296&quot;&gt;#9296&lt;/a&gt; by larskanis&lt;/li&gt;
  &lt;li&gt;Installs bundler 4.0.13 as a default gem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;bundler-release-notes&quot;&gt;Bundler Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements-1&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Do not hard-code permissions for new gem directories during bundle install. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9557&quot;&gt;#9557&lt;/a&gt; by maxfelsher-cgi&lt;/li&gt;
  &lt;li&gt;Clear gem specification cache after acquiring process lock. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9310&quot;&gt;#9310&lt;/a&gt; by ngan&lt;/li&gt;
  &lt;li&gt;Show release date with bundle outdated. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9337&quot;&gt;#9337&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bug-fixes&quot;&gt;Bug fixes:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Apply cooldown to locally installed gem versions. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9582&quot;&gt;#9582&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;security&quot;&gt;Security:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cooldown&lt;/code&gt; to delay newly published gem. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9576&quot;&gt;#9576&lt;/a&gt; by hsbt. See &lt;a href=&quot;/2026/06/03/cooldown-let-new-gems-be-vetted.html&quot;&gt;Cool down before you install&lt;/a&gt; for what it does and how to turn it on.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;manual-installation&quot;&gt;Manual Installation&lt;/h2&gt;

&lt;p&gt;To install RubyGems by hand see the &lt;a href=&quot;https://rubygems.org/pages/download&quot;&gt;Download RubyGems&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;SHA256 Checksums:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;rubygems-4.0.13.tgz&lt;br /&gt;
91088b66de3e57b3865251610a06254e88f5cf268521cd9fd3c9559a33c5a567&lt;/li&gt;
  &lt;li&gt;rubygems-4.0.13.zip&lt;br /&gt;
7b9d20fec6503d738de6b954dbd506bc8ee9ff9266f47f6f382b60464033faa7&lt;/li&gt;
  &lt;li&gt;rubygems-update-4.0.13.gem&lt;br /&gt;
80dabc8ce1243c2d7c4b32f8898df56fc03db5f616ca1cb35bc5af5a8bf1a3e4&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>4.0.12 Released</title>
   <link href="https://blog.rubygems.org/2026/05/20/4.0.12-released.html"/>
   <updated>2026-05-20T00:00:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/05/20/4.0.12-released</id>
   <author><name>Hiroshi SHIBATA</name></author>
   <content type="html">&lt;p&gt;RubyGems 4.0.12 includes enhancements and bug fixes and Bundler 4.0.12 includes enhancements and bug fixes.&lt;/p&gt;

&lt;p&gt;To update to the latest RubyGems you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem update --system [--pre]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To update to the latest Bundler you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem install bundler [--pre]
bundle update --bundler=4.0.12
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;rubygems-release-notes&quot;&gt;RubyGems Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Remove cygwin from WIN_PATTERNS. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9527&quot;&gt;#9527&lt;/a&gt; by fd00&lt;/li&gt;
  &lt;li&gt;Installs bundler 4.0.12 as a default gem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bug-fixes&quot;&gt;Bug fixes:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Fall back to lockfile version when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BUNDLE_VERSION&lt;/code&gt; is “lockfile”. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9545&quot;&gt;#9545&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Read &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BUNDLE_VERSION&lt;/code&gt; env var in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BundlerVersionFinder&lt;/code&gt;. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9538&quot;&gt;#9538&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;bundler-release-notes&quot;&gt;Bundler Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements-1&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Make &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle config get&lt;/code&gt; return status 1 when the value is not set. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9505&quot;&gt;#9505&lt;/a&gt; by willnet&lt;/li&gt;
  &lt;li&gt;Use Pathname#absolute?. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9529&quot;&gt;#9529&lt;/a&gt; by nobu&lt;/li&gt;
  &lt;li&gt;Deprecate parsing non-lockfile content in LockfileParser. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9502&quot;&gt;#9502&lt;/a&gt; by kurotaky&lt;/li&gt;
  &lt;li&gt;Print a warning for a potential confusion from the indirect dependencies. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/5029&quot;&gt;#5029&lt;/a&gt; by junaruga&lt;/li&gt;
  &lt;li&gt;Respect Gemfile bundler setting in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bundler.setup&lt;/code&gt;. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/4892&quot;&gt;#4892&lt;/a&gt; by godfat&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bug-fixes-1&quot;&gt;Bug fixes:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Gracefully handle missing checksums in Compact Index. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9492&quot;&gt;#9492&lt;/a&gt; by jneen&lt;/li&gt;
  &lt;li&gt;Skip git source exclusion when lockfile cannot backfill. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9544&quot;&gt;#9544&lt;/a&gt; by yahonda&lt;/li&gt;
  &lt;li&gt;Fix bundle config gemfile unset behavior. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9514&quot;&gt;#9514&lt;/a&gt; by afurm&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;manual-installation&quot;&gt;Manual Installation&lt;/h2&gt;

&lt;p&gt;To install RubyGems by hand see the &lt;a href=&quot;https://rubygems.org/pages/download&quot;&gt;Download RubyGems&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;SHA256 Checksums:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;rubygems-4.0.12.tgz&lt;br /&gt;
d4a125cb0df8afccda92c976b7170a977fccb3a133daa55ec45d681478912a50&lt;/li&gt;
  &lt;li&gt;rubygems-4.0.12.zip&lt;br /&gt;
5be0ec39295602e83b339b1a0326db1e383ea267594a9a3cd401f7aff06d5228&lt;/li&gt;
  &lt;li&gt;rubygems-update-4.0.12.gem&lt;br /&gt;
7ad8f633a3e4217b6c23455f22fd145a3c5434f8b3b49999a4fde6493318095e&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>4.0.11 Released</title>
   <link href="https://blog.rubygems.org/2026/04/30/4.0.11-released.html"/>
   <updated>2026-04-30T00:00:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/04/30/4.0.11-released</id>
   <author><name>Hiroshi SHIBATA</name></author>
   <content type="html">&lt;p&gt;RubyGems 4.0.11 includes enhancements and Bundler 4.0.11 includes enhancements, bug fixes and documentation.&lt;/p&gt;

&lt;p&gt;To update to the latest RubyGems you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem update --system [--pre]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To update to the latest Bundler you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem install bundler [--pre]
bundle update --bundler=4.0.11
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;rubygems-release-notes&quot;&gt;RubyGems Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Add commented-out rubygems_mfa_required to bundle gem template. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9487&quot;&gt;#9487&lt;/a&gt; by MatheusRich&lt;/li&gt;
  &lt;li&gt;Clarify the name and meaning of the first argument to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem spec&lt;/code&gt;. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9476&quot;&gt;#9476&lt;/a&gt; by eregon&lt;/li&gt;
  &lt;li&gt;Installs bundler 4.0.11 as a default gem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;bundler-release-notes&quot;&gt;Bundler Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements-1&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Update gem creation guide URL to rubygems.org. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9500&quot;&gt;#9500&lt;/a&gt; by nissyi-gh&lt;/li&gt;
  &lt;li&gt;Lock the checksum of Bundler itself in the lockfile. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9366&quot;&gt;#9366&lt;/a&gt; by Edouard-chin&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bug-fixes&quot;&gt;Bug fixes:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Fix installing gems with native extensions + transitive dependencies. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9477&quot;&gt;#9477&lt;/a&gt; by nicholasdower&lt;/li&gt;
  &lt;li&gt;Fix the bundler version not being updated in dev/test lockfile. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9463&quot;&gt;#9463&lt;/a&gt; by Edouard-chin&lt;/li&gt;
  &lt;li&gt;Ensure the release CI doesn’t break due to the Bundler checksum feature. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9436&quot;&gt;#9436&lt;/a&gt; by Edouard-chin&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;documentation&quot;&gt;Documentation:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Fix formatting for BUNDLE_PREFER_PATCH variable in man page. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9474&quot;&gt;#9474&lt;/a&gt; by toy&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;manual-installation&quot;&gt;Manual Installation&lt;/h2&gt;

&lt;p&gt;To install RubyGems by hand see the &lt;a href=&quot;https://rubygems.org/pages/download&quot;&gt;Download RubyGems&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;SHA256 Checksums:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;rubygems-4.0.11.tgz&lt;br /&gt;
95fe9d9d5293d022ceb29afac56eee4e2d46f901de309ab46915ff84d5ec68e8&lt;/li&gt;
  &lt;li&gt;rubygems-4.0.11.zip&lt;br /&gt;
1b5800bf8b94d0ac4027d71efe8eace3d1ec24442397731cd0c6b16ecfa30163&lt;/li&gt;
  &lt;li&gt;rubygems-update-4.0.11.gem&lt;br /&gt;
d851e6dfc3d1984952c1f6129798472baa899d3ad84ea9eb687cd1237b341068&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Scaling Ruby&apos;s defenses with AI</title>
   <link href="https://blog.rubygems.org/2026/04/29/scaling-rubys-defenses-with-ai.html"/>
   <updated>2026-04-29T00:00:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/04/29/scaling-rubys-defenses-with-ai</id>
   <author><name>Colby Swandale</name></author>
   <content type="html">&lt;p&gt;On April 23rd, we submitted a vulnerability report to the &lt;a href=&quot;https://github.com/sparklemotion/nokogiri&quot;&gt;Nokogiri&lt;/a&gt; maintainers. It was the first one our team has filed using AI-assisted scanning. The maintainers accepted the report and published it as &lt;a href=&quot;https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-c4rq-3m3g-8wgx&quot;&gt;GHSA-c4rq-3m3g-8wgx&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The same week, news broke that Mythos, Anthropic’s most capable security model, had been accessed by unauthorized users through a third-party vendor. According to Anthropic, Mythos has identified thousands of zero-day vulnerabilities across every major operating system and web browser, &lt;a href=&quot;https://red.anthropic.com/2026/mythos-preview/&quot;&gt;including a 17-year-old remote code execution flaw in FreeBSD and a 27-year-old bug in OpenBSD&lt;/a&gt;. Two stories on the same shift, one from each side of it. The capability gap between attackers and defenders just widened, and most open source ecosystems have nothing to close it with.&lt;/p&gt;

&lt;p&gt;Anthropic is bringing some open source maintainers into &lt;a href=&quot;https://www.anthropic.com/glasswing&quot;&gt;Project Glasswing&lt;/a&gt;. Ruby is on the list, and agreements signed, but the access is not live yet. We cannot afford to be on the wrong side of that gap.&lt;/p&gt;

&lt;p&gt;We have been working on the defender side. &lt;a href=&quot;https://rubygems.org&quot;&gt;RubyGems&lt;/a&gt; hosts roughly 190,000 gems, and you cannot audit them all. The &lt;a href=&quot;https://openssf.org/projects/criticality-score/&quot;&gt;OpenSSF Criticality Score&lt;/a&gt; lets us focus on the gems whose compromise would cascade through the rest of the ecosystem. We’re looking at those first.&lt;/p&gt;

&lt;p&gt;We are using Claude Opus 4.7 to surface candidate vulnerabilities. A human reviewer triages, verifies, and writes up every finding before anything reaches a maintainer. None of this work happens without backing. &lt;a href=&quot;https://alpha-omega.dev/&quot;&gt;Alpha Omega&lt;/a&gt;, a project of the &lt;a href=&quot;https://openssf.org&quot;&gt;OpenSSF&lt;/a&gt; at the Linux Foundation, is &lt;a href=&quot;https://www.linuxfoundation.org/press/linux-foundation-announces-12.5-million-in-grant-funding-from-leading-organizations-to-advance-open-source-security&quot;&gt;sponsoring this work&lt;/a&gt;. Anthropic is providing the model access we need to operate at the scale it needs.&lt;/p&gt;

&lt;p&gt;The bug we found in Nokogiri is a regex backtracking pathology in the CSS tokenizer. A short, unterminated attribute selector could hang the Ruby process indefinitely because the tokenizer’s regex tries to interpret each escape sequence two different ways and explores an exponential number of possibilities before giving up. Every public Nokogiri CSS entry point routes through this tokenizer. Most large consumers (Rails, Capybara, Loofah) pass developer-written selectors and were unaffected. But any application that lets user input flow into a CSS selector (scrapers, feed readers) was exposed to an unauthenticated denial-of-service via a payload small enough to fit in a request parameter.&lt;/p&gt;

&lt;p&gt;ReDoS bugs are a sweet spot for model-assisted finding. They are hard to spot by reading code and easy to verify by running them. Opus 4.7 flagged the ambiguous STRING rule in the CSS tokenizer and proposed a payload to exercise it: an unterminated attribute selector followed by a run of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\a&lt;/code&gt; escape sequences. I ran it. Parsing took 6ms at fifteen escape sequences and timed out past five seconds at twenty-four. Each added escape roughly quadrupled the runtime, which is what catastrophic backtracking looks like. I wrote up the report. The Nokogiri maintainers accepted it, patched the bug, and published the advisory. The fix is in.&lt;/p&gt;

&lt;p&gt;Open source maintainers are already drowning in AI-generated security reports that don’t hold up. Each one wastes a maintainer’s day and makes the next legitimate report harder to act on. We are not going to be part of that.&lt;/p&gt;

&lt;p&gt;Opus 4.7 is the most capable model we have access to right now, and it produced a real advisory in one of the most widely used gems in the ecosystem. We are working with Anthropic to gain access to Mythos through Project Glasswing. We did not need to wait for it to find this bug, and we will not wait to find the next one.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://rubycentral.org&quot;&gt;RubyCentral&lt;/a&gt; is hiring a small team of security engineers to scale this work. The job is to run AI-assisted reviews against the most critical gems on rubygems.org, verify findings, and earn the kind of relationship with maintainers where an advisory from us is taken seriously and acted on quickly. If you have done open source security work in any ecosystem and want to do it at scale, we would like to hear from you. Please reach out to &lt;a href=&quot;mailto:oss@rubycentral.org&quot;&gt;oss@rubycentral.org&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We submitted our first report on April 23rd. There are 190,000 more gems to look at.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Update, 30 April 2026:&lt;/strong&gt; An earlier version of this post said &lt;em&gt;“Ruby is not in yet”&lt;/em&gt; in reference to Project Glasswing. We have been invited into the program, but the access is not live yet. The line has been clarified to reflect that.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
 </entry>
 
 <entry>
   <title>rubygems.org has a public roadmap</title>
   <link href="https://blog.rubygems.org/2026/04/15/rubygems-org-has-a-public-roadmap.html"/>
   <updated>2026-04-15T00:00:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/04/15/rubygems-org-has-a-public-roadmap</id>
   <author><name>Colby Swandale</name></author>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; has been a busy project. This past year we shipped formal policies for the first time in the registry’s history, launched the Organizations private beta, and made some meaningful security improvements to how gems get validated and how compromised passwords get caught. A lot of that work happened quietly. If you wanted to know where things were headed, you had to catch the right conference talk or subscribe to the right newsletter, and even then you’d only get pieces. The roadmap puts it in one place.&lt;/p&gt;

&lt;p&gt;The roadmap covers work at different stages, from Organizations moving toward general availability to longer-horizon work on security tooling, gem archival, and acceptable use policies. The full list is on &lt;a href=&quot;https://github.com/orgs/rubygems/projects/21&quot;&gt;the board&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As the registry has grown, the stakes of each change have grown with it. Those changes ripple out to gem authors, client maintainers, and anyone who depends on the ecosystem being stable. Getting that right requires input from people outside the core team. Contributors from both the RubyGems client team and Shopify are already working with us on making native gems a better experience for the Ruby community. A public roadmap makes more of that possible.&lt;/p&gt;

&lt;p&gt;If you see something on the &lt;a href=&quot;https://github.com/orgs/rubygems/projects/21&quot;&gt;roadmap&lt;/a&gt; that affects your work, leave a comment on the issue. If something’s missing that you think should be there, &lt;a href=&quot;https://github.com/rubygems/roadmap/issues/new&quot;&gt;open an issue&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The roadmap is public now. We’re curious what the community does with it.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Protecting rubygems.org from the outside in: DoS prevention and compromised passwords</title>
   <link href="https://blog.rubygems.org/2026/04/09/protecting-rubygems-from-the-outside-in.html"/>
   <updated>2026-04-09T00:00:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/04/09/protecting-rubygems-from-the-outside-in</id>
   <author><name>Colby Swandale</name></author>
   <content type="html">&lt;p&gt;Every gem published to &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; ends up running on someone’s computer. It’s up to &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; to ensure that each gem contains what it claims, that its metadata is well-formed, and that the person who pushed it is who they say they are.&lt;/p&gt;

&lt;p&gt;We’ve been chipping away at that. Over the past few months, we shipped two changes that tighten &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt;’s defences at very different layers: stronger validation of gem contents at push time, and integration with Have I Been Pwned to catch compromised passwords at login.&lt;/p&gt;

&lt;h2 id=&quot;what-rubygemsorg-checks-when-you-gem-push&quot;&gt;What &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; checks when you gem push&lt;/h2&gt;

&lt;p&gt;A RubyGem is actually just a regular tar file, which contains 3 sections: the code, metadata, and checksums, which you can inspect for yourself.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gem fetch rails
Fetching rails-8.1.3.gem
Downloaded rails-8.1.3

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;tar&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-xvf&lt;/span&gt; rails-8.1.3.gem
x metadata.gz
x data.tar.gz
x checksums.yaml.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; closely inspects all 3 of these files when a gem is published, but the ones we’re looking at are the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;metadata&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checksums.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checksums.yaml&lt;/code&gt; certifies the integrity hash of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data.tar.gz&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;metadata.gz&lt;/code&gt; with a sha256 after &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem build&lt;/code&gt;. If someone tampers with the code directly, the checksums won’t match and &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; rejects the push immediately. Checksums are the easy part.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;metadata.gz&lt;/code&gt; has the serialised YAML of the gem metadata, generated from the gemspec during &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem build&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;s&quot;&gt;--- !ruby/object:Gem::Specification&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;rails&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;!ruby/object:Gem::Version&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;8.1.3&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ruby&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;authors&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;David Heinemeier Hansson&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;bindir&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;bin&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cert_chain&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;1980-01-02 00:00:00.000000000 Z&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;!ruby/object:Gem::Dependency&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;activesupport&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;requirement&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;!ruby/object:Gem::Requirement&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;requirements&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;=&apos;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;!ruby/object:Gem::Version&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;8.1.3&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;:runtime&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;prerelease&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;version_requirements&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;!ruby/object:Gem::Requirement&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;requirements&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;=&apos;&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;!ruby/object:Gem::Version&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;8.1.3&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When a gem is pushed, &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; deserialises the YAML and reconstructs a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gem::Specification&lt;/code&gt; object from it. It then validates the result, checking that the name and version are well-formed, that the declared dependencies are valid, that the person pushing is authorised. This is where gem validation gets complex.&lt;/p&gt;

&lt;h2 id=&quot;exploiting-the-validation-process&quot;&gt;Exploiting the validation process&lt;/h2&gt;

&lt;p&gt;This process of reconstructing the gemspec YAML into a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gem::Specification&lt;/code&gt; object invites a class of exploitation called &lt;a href=&quot;https://owasp.org/www-community/vulnerabilities/Insecure_Deserialization&quot;&gt;insecure deserialisation&lt;/a&gt; that would allow a crafted YAML to attack &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This isn’t a theoretical concern. In 2017, a &lt;a href=&quot;https://blog.rubygems.org/2017/10/09/unsafe-object-deserialization-vulnerability.html&quot;&gt;security researcher discovered&lt;/a&gt; that rubygems.org was using a bare &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YAML.load&lt;/code&gt; to deserialise checksums inside gem files, a vulnerability that had potentially been present since 2012. The team patched it within hours by switching to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YAML.safe_load&lt;/code&gt;, which restricts which Ruby objects can be instantiated from a document. But that only narrowed the problem. Even with a precise allowlist of classes and objects, malicious gems could still exploit the deserialisation process to exhaust memory or CPU before any validation even ran, causing rubygems.org servers to stop working.&lt;/p&gt;

&lt;h2 id=&quot;validating-gems-without-gemspecification&quot;&gt;Validating gems without &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gem::Specification&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;The fix was to stop trusting the YAML to tell &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; what to do with itself.&lt;/p&gt;

&lt;p&gt;This was largely &lt;a href=&quot;https://bsky.app/profile/tenderlove.dev&quot;&gt;Aaron Patterson’s&lt;/a&gt; (tenderlove) work. He designed and built the AST-based approach from the ground up. Rather than handing the document to Ruby and letting it materialise objects, we traverse the parsed tree ourselves and extract only the values we expect to find. The YAML never gets to decide what gets instantiated. We also validate the structure against a schema derived from the real thing: Aaron audited all 180,000 gems published on &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; and built a tool to validate them against it. Some very old gems turned up edge cases we deliberately chose not to handle. If those gems were pushed today, they’d be rejected, but these gems that haven’t seen a new version in years almost certainly never will be. His contribution here is greatly appreciated.&lt;/p&gt;

&lt;p&gt;The result is that an entire class of exploitation (using malformed metadata to attack the push endpoint itself) is no longer possible. The attack surface doesn’t exist anymore.&lt;/p&gt;

&lt;h2 id=&quot;compromised-passwords-and-the-supply-chain&quot;&gt;Compromised passwords and the supply chain&lt;/h2&gt;

&lt;p&gt;Gem validation protects &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; from what gets pushed. But there’s a separate persistent threat: who’s doing the pushing.&lt;/p&gt;

&lt;p&gt;Package registries are high-value targets for credential stuffing. If an attacker gets hold of a developer’s reused password from an unrelated breach, they can log in as that developer and push a malicious version of a legitimate gem. The code is signed by a trusted account. The checksums match. Everything looks right, because as far as &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; can tell, it is.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://haveibeenpwned.com&quot;&gt;Have I Been Pwned&lt;/a&gt; (HIBP) is a service run by security researcher &lt;a href=&quot;https://www.troyhunt.com&quot;&gt;Troy Hunt&lt;/a&gt; that tracks passwords exposed in known data breaches. At the time of writing, it contains over 10 billion compromised passwords. &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; now checks against it at login, registration and password resets.&lt;/p&gt;

&lt;h2 id=&quot;checking-passwords-without-exposing-them&quot;&gt;Checking passwords without exposing them&lt;/h2&gt;

&lt;p&gt;The obvious concern with checking your password against a third-party service is privacy. &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; never sends your password, or even a full hash of it, to HIBP.&lt;/p&gt;

&lt;p&gt;Instead, it uses &lt;a href=&quot;https://www.troyhunt.com/understanding-have-i-been-pwneds-use-of-sha-1-and-k-anonymity/&quot;&gt;HIBP’s k-anonymity model&lt;/a&gt;. When you log in, &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; computes a SHA-1 hash of your password and sends only the first 5 characters of that hash to the HIBP API. HIBP returns a list of all hashed passwords in its database that start with those 5 characters. &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; then checks that list locally. Your full password hash never leaves our servers.&lt;/p&gt;

&lt;p&gt;If your password appears in the results, &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; blocks the session and shows a warning explaining your password has been found in a known breach. You’ll need to reset your password before you can log in again.&lt;/p&gt;

&lt;p&gt;Since shipping, it’s detected 1,166 accounts with compromised passwords. Because rubygems.org hashes passwords with bcrypt, we’ve never been able to inspect the strength of passwords in the database directly. This is the first real window into how widespread the problem is, and a way to start course correcting it.&lt;/p&gt;

&lt;h2 id=&quot;shipping-the-work&quot;&gt;Shipping the work&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; serves almost a billion gem downloads every single day. Every Ruby application, from side projects to the infrastructure powering large parts of the internet, depends on the integrity of what we distribute.&lt;/p&gt;

&lt;p&gt;These two changes address the supply chain at different layers: one at the moment a gem is built and pushed, the other at the moment a person logs in. Neither is glamorous. Validating YAML ASTs and hashing password prefixes don’t ship in a splash announcement. But this is the work: closing specific, real attack vectors before someone finds them for you. If you want to follow along or get involved, everything happens in the open at &lt;a href=&quot;https://github.com/rubygems/rubygems.org&quot;&gt;github.com/rubygems/rubygems.org&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>4.0.10 Released</title>
   <link href="https://blog.rubygems.org/2026/04/08/4.0.10-released.html"/>
   <updated>2026-04-08T00:00:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/04/08/4.0.10-released</id>
   <author><name>Hiroshi SHIBATA</name></author>
   <content type="html">&lt;p&gt;RubyGems 4.0.10 includes enhancements and bug fixes and Bundler 4.0.10 includes enhancements and bug fixes.&lt;/p&gt;

&lt;p&gt;To update to the latest RubyGems you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem update --system [--pre]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To update to the latest Bundler you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem install bundler [--pre]
bundle update --bundler=4.0.10
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;rubygems-release-notes&quot;&gt;RubyGems Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Ignore warnings with spec different platforms. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/8508&quot;&gt;#8508&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Better algorithm for sorting gem version. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9421&quot;&gt;#9421&lt;/a&gt; by Edouard-chin&lt;/li&gt;
  &lt;li&gt;Update SPDX license list as of 2026-02-20. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9434&quot;&gt;#9434&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Installs bundler 4.0.10 as a default gem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bug-fixes&quot;&gt;Bug fixes:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Register native extension files in default spec map. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9431&quot;&gt;#9431&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Fix NoMethodError in Gem.try_activate when activation conflicts occur. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9404&quot;&gt;#9404&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;bundler-release-notes&quot;&gt;Bundler Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements-1&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Ignore warnings with spec different platforms. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/8508&quot;&gt;#8508&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Improve error message when current platform is not in lockfile. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9439&quot;&gt;#9439&lt;/a&gt; by 55728&lt;/li&gt;
  &lt;li&gt;Cache package version selection. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9410&quot;&gt;#9410&lt;/a&gt; by Edouard-chin&lt;/li&gt;
  &lt;li&gt;Check happy path first when comparing gem version. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9417&quot;&gt;#9417&lt;/a&gt; by Edouard-chin&lt;/li&gt;
  &lt;li&gt;[feature] default_cli_command for config what command bundler runs when no specific command is provided. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/8886&quot;&gt;#8886&lt;/a&gt; by jonbarlo&lt;/li&gt;
  &lt;li&gt;Introduce a fast path for comparing Gem::Version. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9414&quot;&gt;#9414&lt;/a&gt; by Edouard-chin&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bug-fixes-1&quot;&gt;Bug fixes:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Restore rb_sys dependency for Rust. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9416&quot;&gt;#9416&lt;/a&gt; by bangseongbeom&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;manual-installation&quot;&gt;Manual Installation&lt;/h2&gt;

&lt;p&gt;To install RubyGems by hand see the &lt;a href=&quot;https://rubygems.org/pages/download&quot;&gt;Download RubyGems&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;SHA256 Checksums:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;rubygems-4.0.10.tgz&lt;br /&gt;
6a225b7a8883de45d90c9b3f7ee14391759b286030ba1d1d77588cd7282e6cc7&lt;/li&gt;
  &lt;li&gt;rubygems-4.0.10.zip&lt;br /&gt;
edbb019691ef32e5e086595f54e1bc24bcfe5b9fe77e27aa893c7c752ef190d9&lt;/li&gt;
  &lt;li&gt;rubygems-update-4.0.10.gem&lt;br /&gt;
bd9dcd20076e809467739c868df95bcd628744f63e3b63d9df169d6223dabf6d&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Temporarily disabling language support on rubygems.org</title>
   <link href="https://blog.rubygems.org/2026/04/07/temporarily-disabling-language-support.html"/>
   <updated>2026-04-07T00:00:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/04/07/temporarily-disabling-language-support</id>
   <author><name>Colby Swandale</name></author>
   <content type="html">&lt;p&gt;I’m one of the operators of &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt;. Here’s what’s been happening over the past week, and a temporary change we’re making as a result.&lt;/p&gt;

&lt;p&gt;For the past seven days, &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; has been under sustained bot traffic from many different sources scraping data from every published gem. The volume has been large enough to force the site offline while we respond. The bots are deliberately bypassing the Fastly cache, hitting our origin servers directly.&lt;/p&gt;

&lt;p&gt;The primary target has been our language locale pages, the translated versions of &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt;. Unfortunately, the locale system wasn’t designed to cache easily through a CDN. To protect site stability, we’re temporarily disabling language support while we rearchitect how locale pages are cached.&lt;/p&gt;

&lt;p&gt;We’ll restore language support as soon as we have caching in place that can handle this volume. Thank you for your patience.&lt;/p&gt;

&lt;p&gt;P.S. if you need gem and version data for a project, we publish regular database exports at &lt;a href=&quot;https://rubygems.org/pages/data&quot;&gt;https://rubygems.org/pages/data&lt;/a&gt;. We strongly recommend using those instead of scraping &lt;a href=&quot;https://rubygems.org&quot;&gt;rubygems.org&lt;/a&gt; directly.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>4.0.9 Released</title>
   <link href="https://blog.rubygems.org/2026/03/25/4.0.9-released.html"/>
   <updated>2026-03-25T00:00:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/03/25/4.0.9-released</id>
   <author><name>Hiroshi SHIBATA</name></author>
   <content type="html">&lt;p&gt;RubyGems 4.0.9 includes enhancements, bug fixes and documentation and Bundler 4.0.9 includes enhancements and bug fixes.&lt;/p&gt;

&lt;p&gt;To update to the latest RubyGems you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem update --system [--pre]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To update to the latest Bundler you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem install bundler [--pre]
bundle update --bundler=4.0.9
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;rubygems-release-notes&quot;&gt;RubyGems Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Fix: include owner role in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem owner&lt;/code&gt;. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9403&quot;&gt;#9403&lt;/a&gt; by gjtorikian&lt;/li&gt;
  &lt;li&gt;Installs bundler 4.0.9 as a default gem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bug-fixes&quot;&gt;Bug fixes:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Fix: Ensure trailing slash is added to source URIs added via gem sources. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9055&quot;&gt;#9055&lt;/a&gt; by zirni&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;documentation&quot;&gt;Documentation:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;[DOC] Fix link. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9409&quot;&gt;#9409&lt;/a&gt; by BurdetteLamar&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;bundler-release-notes&quot;&gt;Bundler Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements-1&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Check the git version only &lt;strong&gt;once&lt;/strong&gt; per &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle install&lt;/code&gt;. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9406&quot;&gt;#9406&lt;/a&gt; by Edouard-chin&lt;/li&gt;
  &lt;li&gt;Normalize the number of workers when performing parallel operations. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9400&quot;&gt;#9400&lt;/a&gt; by Edouard-chin&lt;/li&gt;
  &lt;li&gt;Add exponential backoff to bundler retries. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9163&quot;&gt;#9163&lt;/a&gt; by ChrisBr&lt;/li&gt;
  &lt;li&gt;Introduce a priority queue. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9389&quot;&gt;#9389&lt;/a&gt; by Edouard-chin&lt;/li&gt;
  &lt;li&gt;Split the download and install process of a gem. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9381&quot;&gt;#9381&lt;/a&gt; by Edouard-chin&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bug-fixes-1&quot;&gt;Bug fixes:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Retry git fetch without –depth for dumb HTTP transport. Pull request &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9405&quot;&gt;#9405&lt;/a&gt; by hsbt&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;manual-installation&quot;&gt;Manual Installation&lt;/h2&gt;

&lt;p&gt;To install RubyGems by hand see the &lt;a href=&quot;https://rubygems.org/pages/download&quot;&gt;Download RubyGems&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;SHA256 Checksums:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;rubygems-4.0.9.tgz&lt;br /&gt;
39b1e2c878946e420116c3c26e4e708c0ddbdf7cd4a13c48dd0fc0774c7add8d&lt;/li&gt;
  &lt;li&gt;rubygems-4.0.9.zip&lt;br /&gt;
d77dfd4baabcdc5b0a268f79332239bbbe2647f78d40778c243beace61d856a6&lt;/li&gt;
  &lt;li&gt;rubygems-update-4.0.9.gem&lt;br /&gt;
e1c0b84abaf481a4e0553d666986156090399afcc099aa18cac6fabbddc45514&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>4.0.8 Released</title>
   <link href="https://blog.rubygems.org/2026/03/11/4.0.8-released.html"/>
   <updated>2026-03-11T00:00:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/03/11/4.0.8-released</id>
   <author><name>Hiroshi SHIBATA</name></author>
   <content type="html">&lt;p&gt;RubyGems 4.0.8 includes enhancements and documentation and Bundler 4.0.8 includes enhancements and bug fixes.&lt;/p&gt;

&lt;p&gt;To update to the latest RubyGems you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem update --system [--pre]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To update to the latest Bundler you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem install bundler [--pre]
bundle update --bundler=4.0.8
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;rubygems-release-notes&quot;&gt;RubyGems Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Use JSON for cargo metadata parsing. Pull request
&lt;a href=&quot;https://github.com/ruby/rubygems/pull/9373&quot;&gt;#9373&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Fix NameError in Gem::Request.get_proxy_from_env when requiring
rubygems/request directly. Pull request
&lt;a href=&quot;https://github.com/ruby/rubygems/pull/9362&quot;&gt;#9362&lt;/a&gt; by afurm&lt;/li&gt;
  &lt;li&gt;Installs bundler 4.0.8 as a default gem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;documentation&quot;&gt;Documentation:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Unify Compact Index API naming. Pull request
&lt;a href=&quot;https://github.com/ruby/rubygems/pull/9372&quot;&gt;#9372&lt;/a&gt; by simi&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;bundler-release-notes&quot;&gt;Bundler Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements-1&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Add a new Bundler config to control how many specs are fetched &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9363&quot;&gt;#9363&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Restrict GitHub Actions workflow permissions for newgem &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9361&quot;&gt;#9361&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bug-fixes&quot;&gt;Bug fixes:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Fix plugin new version not registering &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9355&quot;&gt;#9355&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;manual-installation&quot;&gt;Manual Installation&lt;/h2&gt;

&lt;p&gt;To install RubyGems by hand see the &lt;a href=&quot;https://rubygems.org/pages/download&quot;&gt;Download RubyGems&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;SHA256 Checksums:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;rubygems-4.0.8.tgz&lt;br /&gt;
b18663def26384e467f2594bf27190c580771df0ca7ba444afa1d76609881813&lt;/li&gt;
  &lt;li&gt;rubygems-4.0.8.zip&lt;br /&gt;
205198b7513521d2ba358e6b4df88924601be89b329d2b49fc0c0f55e41b167b&lt;/li&gt;
  &lt;li&gt;rubygems-update-4.0.8.gem&lt;br /&gt;
3465eef02174a0bbad1f8d343eff67a33e7fc6eeb84cf69f1d1ca77ce565045c&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>4.0.7 Released</title>
   <link href="https://blog.rubygems.org/2026/02/25/4.0.7-released.html"/>
   <updated>2026-02-25T00:00:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/02/25/4.0.7-released</id>
   <author><name>Hiroshi SHIBATA</name></author>
   <content type="html">&lt;p&gt;RubyGems 4.0.7 includes enhancements and documentation and Bundler 4.0.7 includes enhancements, bug fixes and documentation.&lt;/p&gt;

&lt;p&gt;To update to the latest RubyGems you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem update --system [--pre]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To update to the latest Bundler you can run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem install bundler [--pre]
bundle update --bundler=4.0.7
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;rubygems-release-notes&quot;&gt;RubyGems Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Add Gem.disable_system_update_message in setup.rb. Pull request
&lt;a href=&quot;https://github.com/ruby/rubygems/pull/9020&quot;&gt;#9020&lt;/a&gt; by hyuraku&lt;/li&gt;
  &lt;li&gt;Print message when signing in with an existing API key. Pull request
&lt;a href=&quot;https://github.com/ruby/rubygems/pull/9312&quot;&gt;#9312&lt;/a&gt; by hsbt&lt;/li&gt;
  &lt;li&gt;Installs bundler 4.0.7 as a default gem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;documentation&quot;&gt;Documentation:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Document gemspecs must be deterministic. Pull request
&lt;a href=&quot;https://github.com/ruby/rubygems/pull/9321&quot;&gt;#9321&lt;/a&gt; by fxn&lt;/li&gt;
  &lt;li&gt;Remove “##” from a comment to require. Pull request
&lt;a href=&quot;https://github.com/ruby/rubygems/pull/9306&quot;&gt;#9306&lt;/a&gt; by tompng&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;bundler-release-notes&quot;&gt;Bundler Release Notes&lt;/h2&gt;

&lt;h3 id=&quot;enhancements-1&quot;&gt;Enhancements:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Don’t check whether a plugin needs to be installed: &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9328&quot;&gt;#9328&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[rust gem] Major improvements for gem scaffolding (rebased) &lt;a href=&quot;https://github.com/ruby/rubygems/pull/8455&quot;&gt;#8455&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Fix(bundler): only preload git sources for requested groups &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9234&quot;&gt;#9234&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Raise error when gem contains capital letters &lt;a href=&quot;https://github.com/ruby/rubygems/pull/5432&quot;&gt;#5432&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bug-fixes&quot;&gt;Bug fixes:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Fix Bundler crashing when it tries to install plugin: &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9335&quot;&gt;#9335&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Run git operations in parallel (take 2): &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9323&quot;&gt;#9323&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Add support for help flag in plugin commands &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9263&quot;&gt;#9263&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;documentation-1&quot;&gt;Documentation:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;[DOC] Fix link in Bundler &lt;a href=&quot;https://github.com/ruby/rubygems/pull/9315&quot;&gt;#9315&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;manual-installation&quot;&gt;Manual Installation&lt;/h2&gt;

&lt;p&gt;To install RubyGems by hand see the &lt;a href=&quot;https://rubygems.org/pages/download&quot;&gt;Download RubyGems&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;SHA256 Checksums:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;rubygems-4.0.7.tgz&lt;br /&gt;
80578da300518eca7abebb4c89ad26e5751ac8a77919f246b4fed67609f919e3&lt;/li&gt;
  &lt;li&gt;rubygems-4.0.7.zip&lt;br /&gt;
e6c46b17a7495a8fdeef91de1bf76d225e0ec4f164e6b88ea5f38f43ca531ba8&lt;/li&gt;
  &lt;li&gt;rubygems-update-4.0.7.gem&lt;br /&gt;
273c1291b85cd5882b10242e3c8463995164bcb2d37c2a92347ecd04fa5ae99a&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Organizations Private Beta</title>
   <link href="https://blog.rubygems.org/2026/02/16/organizations-beta.html"/>
   <updated>2026-02-16T00:00:00+00:00</updated>
   <id>https://blog.rubygems.org/2026/02/16/organizations-beta</id>
   <author><name>Marty Haught</name></author>
   <content type="html">&lt;p&gt;We’re excited to announce that the Organizations feature for RubyGems.org has entered private beta!&lt;/p&gt;

&lt;h3 id=&quot;a-long-time-coming&quot;&gt;A long time coming&lt;/h3&gt;

&lt;p&gt;We started the Organizations work back in 2024 as announced in our &lt;a href=&quot;https://blog.rubygems.org/2024/07/23/june-rubygems-updates.html&quot;&gt;June 2024 RubyGems update&lt;/a&gt;, where we shared our plans to bring organization accounts, memberships, and more precise gem permission controls to the platform. Since then, the team has been steadily building out the feature from refactoring our permissions models to introducing &lt;a href=&quot;https://blog.rubygems.org/2024/11/20/october-rubygems-updates.html&quot;&gt;ownership roles&lt;/a&gt;, building the &lt;a href=&quot;https://blog.rubygems.org/2024/12/20/november-rubygems-updates.html&quot;&gt;organization onboarding experience&lt;/a&gt;, and updating our &lt;a href=&quot;https://guides.rubygems.org/organizations/getting-started/&quot;&gt;guides&lt;/a&gt; to cover how Organizations work.  After more than a year of development, Organizations is ready for real-world feedback.&lt;/p&gt;

&lt;h3 id=&quot;join-the-private-beta&quot;&gt;Join the Private Beta&lt;/h3&gt;

&lt;p&gt;While ready for testing, it’s not ready for general release.  We’re still refining some workflows and welcome feedback on any gaps you encounter.  After talking to our friends at PyPI, we know that a public rollout of a feature like this will not be trivial.  Instead, we’re adding a limited number of private beta organizations to help us refine the feature.  We’ve already onboarded four organizations, with another four accepted into the program.&lt;/p&gt;

&lt;p&gt;We envision Organizations primarily serving publishers with extended teams who manage gem publishing workflows. We’re especially interested in organizations that approach publishing in unusual or non-standard ways as these edge cases will help us build a better feature for everyone.  If you’re interested in participating, please complete our &lt;a href=&quot;https://docs.google.com/forms/d/e/1FAIpQLScDimnhTz7u0o6kpFJEmvu6Dn-IJz5kXaW1vu5sV5qxVzoAkQ/viewform?usp=header&quot;&gt;interest form&lt;/a&gt; to get started.&lt;/p&gt;

&lt;h3 id=&quot;whats-next&quot;&gt;What’s Next&lt;/h3&gt;

&lt;p&gt;We’ll be iterating on the feature based on what we learn from beta participants. Our goal is to open Organizations to the broader community once we’re confident the experience is solid. As we don’t have an anticipated timeline, stay tuned for updates.&lt;/p&gt;
</content>
 </entry>
 

</feed>
