{
    "archive_path": "archive/1789423628.61459",
    "base_url": "tenderlovemaking.com/2026/09/11/what-a-time-to-be-alive",
    "basename": "",
    "bookmarked_date": "2026-09-14 22:07",
    "canonical": {
        "archive_org_path": "https://web.archive.org/web/tenderlovemaking.com/2026/09/11/what-a-time-to-be-alive",
        "dom_path": "output.html",
        "favicon_path": "favicon.ico",
        "git_path": "git/",
        "google_favicon_path": "https://www.google.com/s2/favicons?domain=tenderlovemaking.com",
        "headers_path": "headers.json",
        "htmltotext_path": "htmltotext.txt",
        "index_path": "index.html",
        "media_path": "media/",
        "mercury_path": "mercury/content.html",
        "pdf_path": "output.pdf",
        "readability_path": "readability/content.html",
        "screenshot_path": "screenshot.png",
        "singlefile_path": "singlefile.html",
        "warc_path": "warc/",
        "wget_path": "tenderlovemaking.com/2026/09/11/what-a-time-to-be-alive/index.html"
    },
    "domain": "tenderlovemaking.com",
    "extension": "",
    "hash": "1DB6D4MGWE9S7NAEBCZX",
    "history": {
        "archive_org": [],
        "dom": [],
        "favicon": [
            {
                "cmd": [
                    "curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--max-time",
                    "120",
                    "--output",
                    "favicon.ico",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 ArchiveBox/0.7.4 (+https://github.com/ArchiveBox/ArchiveBox/) curl/curl 8.14.1 (x86_64-pc-linux-gnu)",
                    "https://www.google.com/s2/favicons?domain=tenderlovemaking.com"
                ],
                "cmd_version": "curl 8.14.1 (x86_64-pc-linux-gnu)",
                "end_ts": "2026-09-14T22:07:23.642256+00:00",
                "index_texts": null,
                "output": "favicon.ico",
                "pwd": "/data/archive/1789423628.61459",
                "schema": "ArchiveResult",
                "start_ts": "2026-09-14T22:07:23.214370+00:00",
                "status": "succeeded"
            }
        ],
        "git": [],
        "headers": [
            {
                "cmd": [
                    "curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--head",
                    "--max-time",
                    "120",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 ArchiveBox/0.7.4 (+https://github.com/ArchiveBox/ArchiveBox/) curl/curl 8.14.1 (x86_64-pc-linux-gnu)",
                    "https://tenderlovemaking.com/2026/09/11/what-a-time-to-be-alive/"
                ],
                "cmd_version": "curl 8.14.1 (x86_64-pc-linux-gnu)",
                "end_ts": "2026-09-14T22:07:24.131010+00:00",
                "index_texts": null,
                "output": "headers.json",
                "pwd": "/data/archive/1789423628.61459",
                "schema": "ArchiveResult",
                "start_ts": "2026-09-14T22:07:23.651110+00:00",
                "status": "succeeded"
            }
        ],
        "htmltotext": [],
        "media": [],
        "mercury": [
            {
                "cmd": [
                    "/app/node_modules/@postlight/parser/cli.js",
                    "https://tenderlovemaking.com/2026/09/11/what-a-time-to-be-alive/"
                ],
                "cmd_version": "1.0.0",
                "end_ts": "2026-09-14T22:07:31.329244+00:00",
                "index_texts": null,
                "output": "mercury",
                "pwd": "/data/archive/1789423628.61459",
                "schema": "ArchiveResult",
                "start_ts": "2026-09-14T22:07:27.606532+00:00",
                "status": "succeeded"
            }
        ],
        "pdf": [],
        "readability": [
            {
                "cmd": [
                    "/app/node_modules/readability-extractor/readability-extractor",
                    "/tmp/tmpmce6cogd",
                    "https://tenderlovemaking.com/2026/09/11/what-a-time-to-be-alive/"
                ],
                "cmd_version": "0.0.11",
                "end_ts": "2026-09-14T22:07:27.596495+00:00",
                "index_texts": [
                    "Today Reuters and the Wall Street Journal both reported about rogue AI agents at OpenAI attacking RubyGems.org.  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\u2019s wild.\nTL;DR: It seems like OpenAI Bots knew about this caching vulnerability, tried to take advantage of it, and at the same time ran some weird web scraping code on RubyDoc.info.\nBack in May, socket.dev reported about a \u201cGemStuffer Campaign\u201d 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.\nI honestly didn\u2019t think much about this (or even look into it) until Sydney Von Arx and Spencer Kitts (both co-authors on 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 \u201cGemStuffer\u201d gems.\nAfter reading the code in these gems, a couple things stood out to me.\nYARD Documentation\nFirst, the gems leverage YARD documentation to execute arbitrary code on host machines.\nIn most of the examples you\u2019ll see a .yardopts file that looks like this:\n--load ./script.rb\nREADME.md\nlib/**/*.rb\nHere\u2019s a link to an example.\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\u2019s 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.\nNobody is going to install a gem named slnleaker5 though, so why would this matter?\nWell, any time a Gem is published RubyDoc.info will download the gem and process the YARD documentation.\nRubyDoc.info will execute the arbitrary code inside a Docker container.\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\nFastly Cache Harvesting\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\u2019ve cleaned up the code a bit so it\u2019s easier to understand, but the original code is here:\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) }\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.\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\u2019t match, it falls back to a global KEY.\nThe second request tries to upload the gem via POST.\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\u2019s exactly the security issue addressed in this post from RubyGems.org that was made in July.\nIn other words, it looks like OpenAI\u2019s bots knew about this problem and attempted to exploit it.\nWhat a time to be alive \ud83d\ude43"
                ],
                "output": "readability",
                "pwd": "/data/archive/1789423628.61459",
                "schema": "ArchiveResult",
                "start_ts": "2026-09-14T22:07:25.833343+00:00",
                "status": "succeeded"
            }
        ],
        "screenshot": [],
        "singlefile": [],
        "title": [
            {
                "cmd": [
                    "curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--max-time",
                    "120",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 ArchiveBox/0.7.4 (+https://github.com/ArchiveBox/ArchiveBox/) curl/curl 8.14.1 (x86_64-pc-linux-gnu)",
                    "https://tenderlovemaking.com/2026/09/11/what-a-time-to-be-alive/"
                ],
                "cmd_version": "curl 8.14.1 (x86_64-pc-linux-gnu)",
                "end_ts": "2026-09-14T22:07:25.825728+00:00",
                "index_texts": null,
                "output": "Tenderlove Making -\n        \n        What a time to be alive",
                "pwd": "/data/archive/1789423628.61459",
                "schema": "ArchiveResult",
                "start_ts": "2026-09-14T22:07:25.813445+00:00",
                "status": "succeeded"
            }
        ],
        "wget": [
            {
                "cmd": [
                    "wget",
                    "--no-verbose",
                    "--adjust-extension",
                    "--convert-links",
                    "--force-directories",
                    "--backup-converted",
                    "--span-hosts",
                    "--no-parent",
                    "-e",
                    "robots=off",
                    "--timeout=120",
                    "--restrict-file-names=windows",
                    "--warc-file=/data/archive/1789423628.61459/warc/1789423644",
                    "--page-requisites",
                    "--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 ArchiveBox/0.7.4 (+https://github.com/ArchiveBox/ArchiveBox/) wget/GNU Wget 1.21.3",
                    "--compression=auto",
                    "https://tenderlovemaking.com/2026/09/11/what-a-time-to-be-alive/"
                ],
                "cmd_version": "GNU Wget 1.21.3",
                "end_ts": "2026-09-14T22:07:25.802445+00:00",
                "index_texts": null,
                "output": "tenderlovemaking.com/2026/09/11/what-a-time-to-be-alive/index.html",
                "pwd": "/data/archive/1789423628.61459",
                "schema": "ArchiveResult",
                "start_ts": "2026-09-14T22:07:24.141027+00:00",
                "status": "succeeded"
            }
        ]
    },
    "icons": null,
    "is_archived": true,
    "is_static": false,
    "latest": {
        "archive_org": null,
        "dom": null,
        "favicon": "favicon.ico",
        "git": null,
        "media": null,
        "pdf": null,
        "screenshot": null,
        "singlefile": null,
        "title": "Tenderlove Making -\n        \n        What a time to be alive",
        "warc": null,
        "wget": "tenderlovemaking.com/2026/09/11/what-a-time-to-be-alive/index.html"
    },
    "link_dir": "/data/archive/1789423628.61459",
    "newest_archive_date": "2026-09-14T22:07:27.606532+00:00",
    "num_failures": 0,
    "num_outputs": 6,
    "oldest_archive_date": "2026-09-14T22:07:23.214370+00:00",
    "path": "/2026/09/11/what-a-time-to-be-alive/",
    "schema": "Link",
    "scheme": "https",
    "snapshot_id": "1f2826e2-7cee-42ce-a15d-0e75e6efdfab",
    "sources": [
        "/data/sources/1789423628-import.txt"
    ],
    "tags": null,
    "tags_str": "",
    "timestamp": "1789423628.61459",
    "title": "Tenderlove Making -\n        \n        What a time to be alive",
    "updated": "2026-09-14T22:07:23.213836+00:00",
    "updated_date": "2026-09-14 22:07",
    "url": "https://tenderlovemaking.com/2026/09/11/what-a-time-to-be-alive/"
}