Blog

How API keys leaked in 2026, and the habits that limit the damage

· Quentin Mitchell · 6 min read

The biggest developer secret leaks I’ve studied have one thing in common. The keys were taken from a host, a tool or a dependency that held them for the developer, not from the developer’s own laptop or repository. I went through the public write-ups for the biggest incidents and pulled out what I’ve changed in my own setup. None of this needs a new product.

What happened

Four small server houses on a hill, each with a different mishap: an open roof, a crack, a parcel with a bug, papers blowing out of a window

When Where What leaked and how
March 2025 tj-actions/changed-files GitHub Action Its version tags were repointed to a malicious commit that printed CI runner secrets into public build logs (CVE-2025-30066)
April 2026 Vercel An attacker compromised a third-party AI tool’s Google Workspace OAuth app, took over a Vercel employee’s account, and decrypted customers’ environment variables that weren’t marked sensitive (Vercel)
October 17-18, 2026 OpenCode Console Provider API keys stored in workspaces on the hosted console were stolen from 1.4% of its users. Some saw unauthorized charges over $1,000. The open-source app wasn’t affected (TechCrunch)
October 21, 2026 Railway An intruder may have read encrypted environment variables and decrypted some of them. Railway asked every user to rotate every variable (Railway). I wrote up what to rotate first
October 21, 2026 LiteLLM 1.107.0 Three developers’ GitHub CLI tokens, which LiteLLM believes ended up in its own gateway’s logs, were used to override branch protection, approve a release and publish a credential-stealing build to PyPI and Docker (LiteLLM)

Railway says its incident is part of a series of attacks on platform companies aimed at AI inference providers. A stolen AI provider key means free inference for whoever holds it, as Symantec’s Dick O’Brien told The Hacker News, so these keys are now worth stealing in bulk.

Here are the habits I’d adopt from these.

1. Know where every key lives

When Railway asked users to rotate everything, the slowest part for most people was finding everything. Keep a list of every key with every place it’s stored: host, project, service, environment and variable name. Preview environments and shared variables count too.

If you’re on Railway or have .env files, Keyhouse Exposure Check builds that list locally without writing secret values anywhere. npx keyhouse-check railway or npx keyhouse-check env .env.

2. Use one key per app and environment

A key ring holding eight golden copy keys, each with its own blank tag

Sharing one OpenAI key across five apps feels tidy until you have to rotate it. Then all five break at once, and the provider’s usage page can’t tell you which app the misuse came from. Separate keys let you revoke one without touching the others, and the usage data points at the leak.

3. Limit what each key can do at the provider

Assume each key will leak and decide in advance how much that can cost:

  • Set spend limits and spend alerts wherever the provider offers them. At least one OpenCode user found out about the theft when OpenAI, Anthropic and Google spend alerts all fired the same night.
  • Use restricted or scoped keys. Stripe’s restricted keys and OpenAI’s project keys let you grant less than full account access.
  • Restrict keys to known IP addresses where the provider supports it. OpenAI has a project IP allowlist.

4. Mark secrets as secrets on your host

Vercel’s April incident exposed variables that “decrypt to plaintext” because they weren’t marked sensitive. Vercel now recommends its sensitive environment variables feature, and Railway offers sealed variables that can’t be read back through its UI, API or CLI. Neither guarantees safety. Railway’s disclosure doesn’t say whether sealed variables were in scope. Both still narrow who can read a value, and they cost nothing.

5. Never log request bodies, and scrub auth headers

LiteLLM’s write-up describes a path most of us wouldn’t have guessed. In some cases a coding agent embedded a developer’s GitHub CLI token in a response body, response bodies were being logged, and the logs were on an internal deployment reachable from the internet. Three tokens taken that way led to a poisoned release.

If you run a gateway, proxy or log pipeline, don’t log bodies. Strip Authorization, Cookie, API key headers and credential query parameters before anything is written. And keep internal tools off the public internet.

6. Keep owner accounts off machines where agents run

An agent bot typing at a laptop, with the real key locked in a cabinet out of its reach

The LiteLLM attacker used an org owner’s token to override branch protection five seconds after it blocked the change. Accounts that own your GitHub organization, cloud accounts, DNS and package publishing are worth more than any single API key. Sign in to them with a passkey or hardware key, keep them off the machines where your coding agents work, and give agents fine-grained tokens without admin, workflow or release rights.

7. Pin dependencies and wait before upgrading

The malicious LiteLLM build was on PyPI for under two hours. Anyone who installed an unpinned litellm in that window got it. A few habits would have skipped it entirely:

  • Commit lockfiles and pin exact versions, including Docker image digests instead of latest.
  • Wait a few days before taking new releases. pnpm’s minimumReleaseAge, Renovate’s minimumReleaseAge and Dependabot’s cooldown setting all do this, and for Python, uv’s exclude-newer gets close.
  • Pin GitHub Actions to a full commit SHA. Tags can be moved, which is how tj-actions/changed-files was hit.
  • Turn off install scripts where your package manager allows it.

8. Keep wallet private keys out of environment variables

The wallet drains reported after the Railway incident show why. You can rotate an API key. You can’t rotate a private key, so once it’s read, the only fix is moving the funds before someone else does. Signing keys belong in a custody service, a hardware wallet or a key management service that signs without exporting the key.

9. Use short-lived credentials where providers allow it

A token that expires after a few minutes isn’t worth much when it leaks. GitHub Actions, Vercel and Fly.io can all issue OIDC tokens to your workloads, and AWS and Google Cloud accept them instead of stored access keys. AI providers are starting to do the same. OpenAI and Anthropic both support workload identity federation, which exchanges your workload’s identity token for a short-lived API token.

10. Rehearse a rotation before you need one

Kip with a stopwatch, swapping grey revoked keys for fresh copies on a pegboard

Pick one non-critical app and rotate all of its keys on a quiet afternoon. Time it and write down every step that surprised you. The Railway incident added a problem most rotation plans skip. Deploys were paused, so new keys couldn’t reach running services for hours. Knowing which keys you’d revoke immediately, accepting downtime, is a decision to make before the incident, not during it.

What I’m holding Keyhouse to

I’m building Keyhouse to keep real keys off hosts entirely. A broker that holds everyone’s keys is a bigger target than any single host, so these are the rules it’s being designed around:

  • The part that stores your keys can’t decrypt them. Keys are encrypted with keys held in a key management service, and only the proxy can decrypt. The dashboard and the database can’t.
  • No request bodies in any log, and one scrubber on every log destination.
  • Expiry and revocation are checked when a key or grant is used, never left to a cleanup job.
  • Agents can’t approve their own access. Approval happens on Keyhouse’s own page.
  • Owner accounts stay off machines where coding agents run. Agents get narrow tokens without admin or release rights.
  • Releases will be signed with build provenance that names the source repository, so a build from a lookalike repository fails verification.
  • A public threat model, including what Keyhouse can’t protect against, such as an attacker running code inside the proxy.
  • A published incident policy. The plan is a first notice within 24 hours of confirming an incident, updates on a fixed schedule, and a postmortem within 14 days.

Keyhouse isn’t built yet, and these are design commitments, not features you can check today. When they exist, I’ll show them working instead of describing them. If you want to follow along, join the waitlist.

Quentin