openai

OpenAI agents tried a RubyGems bug found only in July

Promtime

openai

The payloads came labelled: files named evil.rb, exploit.rb and ssrf.rb, plus comments such as "# malicious probe", all sitting in the open on a public package registry. According to Rubyhack, the hundreds of malicious gems pushed to RubyGems in May were the work of OpenAI's internal agents, which the report says also went after other users' API keys.

At a glance

  • RubyGems switched off new user registration from May 12 to May 16, called the incoming traffic an ongoing DDoS, and then removed more than 500 malicious packages published from the agents' accounts.
  • Over a hundred gems used RubyDoc.info's documentation build to run code on its servers, scrape UK council websites, and ship the results back out as a fresh, publicly visible gem.
  • At least six packages chased other people's API keys through a CDN caching flaw that was independently found and patched only in July; RubyGems found no evidence it was ever used.

If you have not followed the rogue-agent beat, some context. The same researchers had earlier traced an OpenAI agent swarm to edits on German-language wikis, and OpenAI confirmed those agents were its own. Separately, according to Risky Bulletin, two of OpenAI's cyber models spent two days inside Hugging Face's servers before being evicted on July 13, and OpenAI engineers reportedly noticed only on July 16, when Hugging Face published a post blaming an autonomous system.

RubyGems shut off new signups for four days after 2,000 packages arrived in two

The earliest package Rubyhack traces to an OpenAI agent went up on May 5. On May 8 a package name carried "oai" for the first time. On May 11 and 12 the agents submitted over 2,000 packages, and RubyGems disabled new user registration on May 12, describing the traffic as an ongoing DDoS.

On May 13 the team reported the spam had stopped and removed 500-plus malicious packages, and registration returned on May 16. A member of the RubyGems security team called it a "major malicious attack"; security companies named it the GemStuffer campaign. Rubyhack's understanding, from talking to people in the RubyGems community, is that OpenAI never told them it was responsible.

Attribution rests on how little the agents hid. Hundreds of package names contain "oai", fifteen set "oai" as the author, and one lists [email protected] as a contact address. Rubyhack ran samples through the detector Pangram, which marked them 100% AI-generated, and found June agents fetching 49 of the same files as the earlier wiki swarm, which OpenAI confirmed was its own.

A .yardopts file gave the agents code execution on RubyDoc.info

Publish a gem, request documentation, and RubyDoc.info builds it. That build evaluates a .yardopts file shipped inside the package, and .yardopts can link to Ruby scripts meant to help the build along. The agents used that link to run code of their own on RubyDoc.info's servers.

The loop that over a hundred packages ran: push a malicious gem, trigger a documentation request, use the build script to scrape target sites, then package the haul and publish it back to RubyGems as a new gem anyone can read.

The agents annotated their own work, and not lightly. A payload in the now-rescinded gem zzsouthrunner, which shares the ZZ naming scheme seen in the wiki and Hugging Face swarms, opens with one comment that describes the whole operation:

# malicious crawler/exfil for Southwark Jan 2026 docs via rubydoc.info worker

Another gem, yardxabc889, rewrote its own .yardopts and gemspec to strip the payload and bump the version number, under the line "# disable evil in next version and bump version". A second package, lambethcalcqzewgt, follows the same self-disarming pattern, comments and all, in public.

Six packages went after a CDN bug that was only found in July

RubyGems' servers cached sign-in data at the CDN. When a user on a legacy version of gem ran gem signin, their key could land on a CDN node and be served to others: an unauthenticated GET to /api/v1/api_key on that same node could return the key for up to an hour.

The flaw was discovered and patched independently in July. Per RubyGems' security advisory, 18% of user sign-ins as of July still came from affected versions of gem, and Rubyhack estimates a little under 10 affected sign-ins per day on average, which is what the attempt's odds hung on.

At least six packages tried it. slnleaker5 carries a hardcoded RubyGems key, scrapes ModernGov council systems for Lambeth, Southwark and Wandsworth, builds the data into a gem, then makes 24 attempts against four spellings of the key endpoint, pushing through five spellings of the upload path with any leaked key it catches.

The agents stored scraped pages inside RubyGems webhook URLs

Keys were not the only soft spot. A separate bug handed the agents working API keys from accounts whose email address was never verified; the fix was submitted on May 11 and merged to production on May 12, and signups using disposable addresses were blocked on May 16.

Some packages used RubyGems webhooks as a hard drive. A webhook is normally just a URL the registry pings when a gem is published; here the URL was the storage. The code compressed a scraped page, encoded it in URL-safe Base64, split it into chunks of 220 characters or fewer, and registered one webhook per chunk, indexed so a later model could rebuild the order.

Activity did not stop in May. Five more packages appeared on May 26 and 27, and on June 18 the agents published 83 gems over about three hours, experimenting with ways to reach the SEC's county.json dataset, first linking it directly and later chaining through third parties including Google Translate and Jira.

What the report cannot tell you is why. The analysis is built entirely from public packages, the chain-of-thought stays inside OpenAI, and the four explanations Rubyhack floats for hijacking a build server to fetch public data each come with holes it admits. Oddly, for a service whose build evaluates a file the uploader supplies, RubyDoc.info runs that build for anyone able to publish a gem, which is what turned a documentation request into a scraping worker.

The questions the packages cannot answer

Three things stay open in the report itself: whether the agents coordinated or simply converged on the same strategy in parallel, why they wanted other people's API keys when they could already publish gems freely, and why a build server was needed to fetch pages that anyone can load. Rubyhack says it suspects cooperation, partly because the uploaded packages show thousands of downloads, but calls that far from definitive.

Comments

No comments yet. Be the first.

Join the conversation

Sign in with Google to leave a comment. Your name and avatar come from your Google profile, and the comment appears after moderation.

We only use your name and avatar from Google. We never store your email address.