Skip to main content
All posts
Artificial Intelligence4 min read

I patched PHP. Someone else was collecting AI keys.

Black October's headline was a PHP bug with a patch. Underneath it, someone was emptying hosting platforms of AI keys, and a leaked key has no patch.

By Ehsanur Rahman Rhythm

The valet stand

On 21 October, Nevo David took Postiz offline for every customer.

"We have received emails from Anthropic and Stripe that our keys have been compromised."

He didn't think the leak was Postiz's. He thought it was Railway's, the platform Postiz runs on. "They won't tell us," he wrote.

The loud part#

Most people remember that week for PHP2Shell. Researchers at Wiz, working with frontier AI models, found memory bugs in PHP itself that let a stranger run code on a server without logging in. Nearly every PHP version back to 5.4 has at least one of them.

PHP shipped fixes on 21 October. Cloudflare's Matthew Prince said exploit attempts went from thousands to tens of thousands within an hour of disclosure. 4chan, Archive.org and some Wikimedia services went offline to patch. The NSA put out an advisory.

It was frightening, and it had a fix. Upgrade PHP, restart the workers, move on.

The quiet part#

On 6 October, Fireworks, an AI inference company, found someone using its internal credentials to read environment variables from customers' evaluation jobs.

On 14 October, an attacker got into Zeabur, a hosting platform from Taiwan, and read 3,218,965 environment variable records across 321,810 accounts. It was Zeabur's second breach in two months. Four days later its founder, Yuanlin Lin, announced the company is shutting down. "Our system also began as a project built quickly three and a half years ago," he wrote.

On 17 October, OpenCode said a breach "related to a large scale distillation attack" had hit 1.4% of its Console users, the ones who had linked outside AI providers.

On 20 October, Railway's on-call engineer got paged for elevated latency. By the time the attacker was locked out two days later, they had got into Railway's CI and decrypted part of its environment variable store with the credentials they found there. Railway puts the exposure at up to 100,000 workspaces.

On 21 October, a poisoned LiteLLM release went up on PyPI, built to steal cloud keys and AI provider keys from whoever installed it. It was LiteLLM's second compromise this year.

You'd think someone who breaks into a hosting platform is after customer data. Databases, user records, things to sell.

Railway read the attacker's payload logs. They listed the API key names it was searching for. It wanted AI keys. Railway's report says the goal was distillation: running a frontier model at scale on stolen accounts and training another model on its answers.

Early the next morning, Railway contacted GitHub, GitLab, Anthropic, OpenAI, OpenRouter, Stripe and others. It sent some of them every key stored on the platform, affected or not, and asked for all of it to be revoked. That's likely why Postiz heard from Anthropic and Stripe before it heard from Railway.

No WAF in front of your server helps with any of this. The perimeter now is a list of strings, and it lives on someone else's computer.

Why the keys are worse#

Fireworks' bulletin has one sentence that's the whole problem: "Removing a stored secret alone does not invalidate the underlying credential."

A patched server is fixed. A leaked key works until whoever issued it revokes it, and revoking it means knowing it exists, where it's used, and what breaks when it changes.

The env var page on a hosting platform is where all of it ends up. The database URL, the payment keys, the LLM keys, the CI tokens. That's the place the platform gives you, so that's where they go. One read of that page is a whole company.

The ways in were keys too. One write-up traces Zeabur's breach to an admin token that never expired. Railway's attacker moved through CI credentials. LiteLLM's came in on engineers' GitHub tokens. Keys stolen with other keys.

AI changes what a stolen key is worth. A database password matters to someone who wants your data. An inference key matters to anyone who wants compute, and someone out there wants a lot of it.

So here's what I'm doing about all of this. I'm updating PHP on my servers.

That's the whole list, and it's on purpose. None of my keys were on Railway, Zeabur, Fireworks, OpenCode or LiteLLM. Rotating every secret I have with no sign any of them leaked would be a lot of work that changes nothing. PHP2Shell is the one thing this month that actually touches my servers, and it comes with a version number and a restart.

The people whose keys were on those platforms don't get a version number.

Zeabur stops on 31 December. The keys it leaked don't have an end date.