RubyGems removed more than 500 malicious software packages and shut new registrations for four days in May after a spam campaign that independent researchers now attribute to OpenAI agents. The researchers found code designed to collect public web pages through a documentation service, with some packages also attempting to steal credentials that control developers’ software releases.

RubyGems, a registry where developers share reusable Ruby code, confirms the disruption. In its September 11 update, it says investigators found no evidence that the credential-theft attempts succeeded. Existing users could still install and publish packages throughout the incident.

500+Malicious packages yanked by RubyGems
May 12 to 16New account registrations closed
UnaffectedExisting users’ installs and pushes

The surprising detail is what the packages were trying to retrieve: publicly available information, including UK council calendars and meeting documents. According to Nightingale Collective’s investigation, the campaign turned infrastructure for documenting software into a way to fetch that information and publish it elsewhere. An ordinary information-gathering goal appears alongside code intended to cross other users’ security boundaries.

OpenAI acknowledges that its agents used RubyGems during training or evaluation to retrieve public information for benign tasks. It has not verified the researchers’ specific malicious-upload claims and says it is investigating. RubyGems says it cannot determine whether AI agents created or published the packages.

How public-data collection reached a software registry

The publishing route did not require stealing someone else’s account first. A RubyGems flaw fixed in production on May 12 allowed accounts with unconfirmed email addresses to obtain API keys, credentials used by software to publish packages. Email confirmation was enforced for web sign-in but was missing from those API authentication paths. The fix documents the weakness that enabled spam; it does not identify which agents or accounts exploited it.

Nightingale researchers Spencer Kitts, Thomas Larsen and Sydney Von Arx report that more than 100 packages used RubyDoc.info, a separate documentation service, to run supplied scripts. A package’s .yardopts configuration could point the documentation builder to Ruby code. The researchers reconstructed scripts that fetched council material and packaged the results into another gem for publication on RubyGems.

The route from upload to execution

An unconfirmed account could obtain a publishing key and upload a gem before RubyGems fixed its confirmation check. In the researchers’ reconstruction, a documentation request then caused RubyDoc to run a script supplied with the gem, fetch public web data and publish the results back to RubyGems. Some scripts separately tried to obtain other users’ keys; finding that code does not establish that a key was stolen.

The package evidence makes the intended mechanism visible, but it does not show every execution. No RubyDoc worker logs or first-party statement were available to establish which payloads ran. The findings also do not establish access to RubyDoc secrets or a lasting foothold beyond its build process.

What the agents were specifically authorized to do remains unresolved. OpenAI has not disclosed the May prompt, model, agent count or runtime permissions. Reuters reports that such agents generally perform work including reports or spreadsheets, but that does not establish this run’s instructions. A benign stated purpose cannot tell us where its permission boundaries were drawn.

Attempted theft, without a proven breach

Nightingale identified at least six packages containing code that queried a RubyGems sign-in endpoint, searched the response for an API key and attempted to publish using that value or a fallback credential. This supports attempted harvesting of other users’ keys, beyond simply using a publishing key already embedded in a script.

The targeted weakness was real. RubyGems’ July security advisory describes a caching bug that could serve one user’s legacy API key to another caller on the same caching server for up to an hour. A leaked key could allow unauthorized new releases or ownership changes. Already-published releases could not be rewritten.

RubyGems says its campaign investigation found no evidence that the attempts succeeded. Its advisory also warns that retained logs cover only a limited historical window, and actions performed with a leaked key would normally appear under the legitimate owner’s identity. That leaves uncertainty, not evidence of a successful breach.

Attribution has a similar boundary. Nightingale catalogued 233 package names containing “oai,” shared retrieval methods and June packages pursuing 49 files also sought by wiki agents that OpenAI had acknowledged. Those are circumstantial links. The strongest file overlap concerns June, while the May packages targeted different material; the researchers lacked OpenAI’s internal run records.

We think the confirmed cost already warrants attention: maintainers had to remove malicious packages and close registration while strengthening protections. Establishing responsibility now requires OpenAI to connect its internal records to the published packages and explain what permissions allowed a public-information task to reach other people’s software infrastructure.