Why are we still handing AI agents API keys? Railway halted all builds on October 21 after an intruder breached the system storing customers' environment variables, with the company stating early investigations indicate the attack was "attempting to obtain AI provider API keys to perform distillation attacks." The Railway incident followed key thefts at Fireworks AI, Zeabur and OpenCode's Console in the preceding weeks, and the same day a poisoned LiteLLM release sat on PyPI for about two hours installing a credential stealer, while the NSA issued an emergency PHP update advisory. The breaches matter because API keys grant full, unattended access to paid model providers, and one solo developer who revoked a leaked Gemini key within minutes of a billing alert still received a $15,400 bill. Why are we still handing AI agents API keys? AI Agents https://www.builder.io/blog/topics/ai-agents Do you want to proceed? An agent wants to run gh pr view . Yes. It wants to read a config file. Sure. It wants to push the branch I asked it to make. Yes, obviously, that's the whole job. I stopped reading these a while ago. Anthropic says Claude Code users approve 93% of permission prompts https://www.anthropic.com/research/claude-code-auto-mode , which makes them less of a question and more of a rhythm game. Eventually I did what a lot of us do and turned the prompts off. So every agent I run can do whatever I can do from my terminal. It can use my GitHub token. It can read the API keys in my .env files. To every service on the other end, my agent is me. I didn't think much about that until October 21, when Railway, a hosting platform a lot of developers deploy to, stopped all builds https://status.railway.com/incident/QH8L8B3E because an intruder had gotten into the system that stores its customers' environment variables. That's where developers keep their keys. The keys were the point That same day, the NSA told every organization running PHP https://www.nsa.gov/Press-Room/Press-Releases-Statements/Press-Release-View/Article/4630238/nsa-advisory-php-updates/ to get ready for an emergency update, and TechCrunch called it a very bad cybersecurity day https://techcrunch.com/2026/10/21/the-internet-is-having-a-very-bad-cybersecurity-day/ . The headlines went to PHP. The story I couldn't stop reading was about keys. Railway said what its intruder was after https://blog.railway.com/p/preliminary-report-october-security-incident : "Early investigations tell us this attack was attempting to obtain AI provider API keys to perform distillation attacks." Distillation means training your own model on another model's answers. It takes a huge number of paid model calls, and it's a lot cheaper when somebody else is paying. Railway wasn't the first. In the weeks before, intruders took the keys customers had stored with Fireworks AI https://fireworks.ai/security/bulletins/october-2026-security-incident , Zeabur https://zeabur.com/blogs/october-2026-security-incident and OpenCode's Console https://techcrunch.com/2026/10/19/hackers-hit-ai-coding-tool-opencode-running-up-charges-on-users-ai-accounts/ , one platform after another. It's easy to see why. A key isn't a password that gets you to a login screen. It's the whole login. It works from anywhere, for whoever holds it, with no two-step code and no "Was this you?" email, and everything it does shows up under your name until somebody notices. API keys are the demo version of sign-in: paste a string, make a call, get an answer. They're perfect for the first five minutes, and we've been running production on them for years. Noticing doesn't save you, either. A solo developer revoked a leaked Gemini key within minutes of a billing alert and still got a $15,400 bill https://www.techradar.com/pro/security/usd15k-bill-destroyed-a-solo-developers-startup-how-hackers-are-using-leaked-google-api-keys-to-go-wild-with-gemini-ai-for-free . Minutes was too late. And we keep keys everywhere. One key gets pasted into a .env file, a hosting dashboard, a CI secret, a gateway like LiteLLM and an agent's shell, and every copy is one more place to steal it from. Railway wasn't the prize. Neither were the others. The keys were. Figure 1: Every place you paste a key is one more place to steal it from, and a thief only needs one copy. My agent is me The breach I keep rereading is LiteLLM's, because in the end it wasn't about AI keys at all. On the morning Railway stopped its builds, a poisoned release of LiteLLM https://docs.litellm.ai/blog/security-incident-oct-21-2026 sat on PyPI for about two hours. LiteLLM connects apps to lots of model providers, so wherever it runs, keys pile up, and the poisoned version installed a credential stealer. Two days later, LiteLLM explained how the attacker got in https://docs.litellm.ai/blog/security-incident-oct-21-2026-attack-chain . The company had been building an experimental Agent Platform, cloud agents that open pull requests on GitHub. In May, a config file holding that platform's master key ended up in a public repo. In LiteLLM's words, "key revocation did not occur." On October 10, someone used it. They asked the platform for its agents' settings and got every one, including the company owner's own GitHub token, which "was not associated with a service account and was not scoped down." From there they collected two maintainers' tokens, and on October 21 they shipped the poisoned release. LiteLLM calls it "a strong illustration of the risks associated with failing to rotate a potentially exposed key." That's one way to put it. Mine: their agents were their owner, and nobody had changed the locks since May. Figure 2: A key nobody revoked in May opened the agents' settings in October, and the owner's own token was sitting in them. I'd like to feel superior. I can't. That's my setup, minus the public repo. Nobody tricked those agents. The attacker never talked to one. They didn't need to: reading an agent's settings was enough to become its owner. Or just ask the agent Sometimes you don't even need the settings. METR is a nonprofit that measures what AI agents can do. In March, an attacker found one of its researchers' agents on a server whose Google sign-in had quietly stopped working, and, in METR's words https://metr.org/blog/2026-08-31-security-update/ , "prompted an agent directly to reveal its model provider API key." It did. Over three weeks, the attacker ran through credits worth about $600,000, which a model developer had given METR for free, on a key there was "no way to put a spending limit on." We hand agents our keys for an understandable reason: the alternative is babysitting. I sign in to a ridiculous number of services every day, and my agents need half of them. If I don't give an agent broad access, I end up logging it into everything, over and over, and approving every move it makes. So I over-permission it. That's the real problem with my agent being me. It isn't only that it can do too much. When something goes wrong, the only thing I can cut off is myself. The grown-up version Part of this is already solved. Cloud AI services like AWS Bedrock, Azure OpenAI and Google's Vertex let a program sign in as itself, and this year OpenAI https://developers.openai.com/api/docs/guides/workload-identity-federation and Anthropic https://claude.com/resources/articles/workload-identity-federation added the same thing. The platform your code runs on, like GitHub Actions, vouches for which job is asking, and the provider hands back credentials that expire within minutes or hours. You set it up once, by telling the provider which repos and jobs to trust. OpenAI and Anthropic call it workload identity federation. It runs on a standard called OIDC, and it leaves no long-lived key in your secrets for anyone to steal. Figure 3: With OIDC, the job proves who it is each time it runs, so no key sits in your secrets waiting to be stolen. The catch is that this works best for code running somewhere that can vouch for it. Plenty of tools, including a lot of coding agents that work with any model, still ask you to paste a key, and Gemini's quickstart starts with one. The keys themselves are getting better, slowly. Anthropic's console now asks when a new key should expire https://platform.claude.com/docs/en/manage-claude/authentication key-expiration , from three hours out to never . Never is for keys you rotate yourself, which works right up until you forget. One platform is done waiting. Vercel says https://vercel.com/blog/death-to-long-lived-static-credentials marketplace vendors that don't support keyless sign-in will get a "Not secure" label by November 30 and be removed in January. Letting my agent be itself So, I gave one of my agents its own Google account: its own address, its own password, its own two-step codes. It signs in to the beta apps I work on with that account, not mine. A week later it got its own OpenRouter account, with a key capped at $20 a month. The key never expires. Sounds bad, I know. But the account is the agent's, so the agent can rotate that key itself, make new keys for new jobs and raise or lower its own caps. I think that's the better pattern: provision agents like people. Give an agent its own inbox, its own accounts and even its own card with a hard spend limit. Then it can work inside those limits, and when something goes wrong, you cut off the agent instead of yourself. That won't stop prompt injection, since a hijacked agent can still use whatever it holds, but it shrinks what there is to use. You can't give an agent a brand-new identity for every task, though. GitHub's terms https://docs.github.com/en/site-policy/github-terms/github-terms-of-service say "You must be a human to create an Account." My agent took that personally. So it keeps one identity, and everything it holds should belong to the task: a capped OpenRouter key made for one job, a GitHub App token that works on one repo and expires after an hour https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/authenticating-as-a-github-app-installation , and a script that revokes all of it when the job ends. Figure 4: With its own accounts and keys that end with the task, my agent can be cut off without cutting off me. What's still missing You could build that today. I've built parts of it. But it's a lot of work https://www.builder.io/blog/why-is-agent-auth-so-hard , and tokens are expensive. We can't keep hacking all of this together ourselves. It should come in the box, the way OIDC does for code in the cloud. Big companies can already buy something close: Microsoft, Okta, Google and AWS sell agent identities. For one developer with a handful of agents, I haven't found anything that ties the inbox, the accounts, the card and the teardown together. A solo developer is who got that $15,400 bill. On October 21, the day Railway stopped its builds, my agent went to sign up for OpenRouter. It clicked "Sign in with Google" and landed in my account, because my session was still sitting in its browser. For a moment there, my agent was me again. We fixed it: signed me out, signed it back in. Now when it reaches a sign-in page, it picks its own account from the list and clicks Continue. Figure 5: The agent can raise its own caps and make a key for every job, but nothing it does gets past the card. A card with a hard limit is what makes the rest come together. An agent can raise its own caps, but not the card's, so whatever goes wrong, the damage stops at a number you picked. And the prompts from the beginning start to sound different. Do you want to proceed? An agent wants to make a new key for a new job. Yes. It wants to raise its own cap. Sure, up to the card. It wants to spend $600,000 because a stranger asked nicely. The card says no. It's still a rhythm game. I'm just not the one playing it.