On October 17, OpenCode posted on X that it "had a security breach last night" affecting 1.4% of OpenCode Console users, "a subset of users who had external providers linked", and that it was working with Anthropic, OpenAI and Google to remediate. The email those users received, as reported by The Hacker News, says provider keys saved in Console workspaces may have been exposed. Within hours, Anthropic's Lydia Hallie said Anthropic had revoked the Claude API keys it believes were affected, and Google's Evan Otero said Google had blocked the exposed Gemini keys. As of October 19, 2026, OpenCode calls the incident ongoing and hasn't said how it happened. I'm not going to guess.
What matters for the rest of us is simpler. An LLM API key is a bearer credential: whoever has the string can spend your money until the provider revokes it. Securing it means fewer places where the string lives, and less damage when one of them leaks anyway.
The checklist, short version
- One key per tool, project and environment.
- Keys that expire, and a rotation you've actually rehearsed.
- Hard spend limits per project, not just alerts.
- Keys only on the server: route handlers, server actions, environment variables. Never
NEXT_PUBLIC_. - A separate, capped, short-lived key for any hosted tool you paste a key into.
- A first-hour plan for when one leaks.
Provider details below come from OpenAI's, Anthropic's and Google's own docs as of October 19, 2026. They change often.
One key per tool, project and environment
If every script, agent and SaaS shares one key, any leak means revoking the key production runs on. With one key per consumer you revoke one thing, and the usage page tells you which consumer was abused.
- OpenAI. Keys live in projects. OpenAI's key safety article says sharing keys is against the Terms of Use and that you can assign permissions to individual keys.
- Anthropic. Workspaces separate environments and spend. New keys are either personal keys, which act as you, or service account keys, and either can be scoped to a single workspace. Personal keys die when their owner leaves the organization, which is what you want. Workspace keys are now documented as legacy.
- Google. Every Gemini key belongs to a Google Cloud project, and usage from all its keys counts toward the project's spend cap (billing docs). Separate caps per tool means separate projects.
Keys that expire, and a rotation you've rehearsed
A key that never expires stays valid for as long as anyone has a copy.
- OpenAI project keys can be created with an expiration date, and admins can enforce a maximum key lifetime at organization or project level.
- Anthropic asks for an expiration when you create a key: 3 hours, 1 day, 7 days, 30 days, a custom duration, or Never. It can't be changed afterwards, an organization policy can remove Never, and Anthropic emails the creator 7 days before expiry for keys that live at least 14 days.
- Google's Gemini key docs don't mention expiry. They tighten keys another way: since May 28, 2026, new AI Studio keys are bound to a service account and restricted to the Gemini API by default, and unrestricted standard keys are rejected.
OpenAI and Google describe the same rotation order: create the replacement, deploy it, verify it works, then revoke the old one. Rehearse it on a quiet day to learn where the key actually lives (production, previews, CI, that cron job) before you have to do it under pressure. OpenAI and Anthropic also document workload identity federation, which swaps the stored key for short-lived tokens on supported cloud workloads: rotation with nothing to rotate.
Hard spend limits, not just alerts
OpenAI's article says it plainly: "Spend alerts alone don't stop API traffic." An email at 3 a.m. is a receipt for money that's already gone.
| Provider | Hard cap | What the docs warn about |
|---|---|---|
| OpenAI | Monthly spend limits per organization or project, with hard enforcement | Enforcement isn't instantaneous; hard limits can also block legitimate requests |
| Anthropic | Monthly spend limit per workspace, below the organization limit | Can't be set on the Default Workspace |
| Monthly project spend cap in AI Studio, plus tier caps per billing account | Experimental, around 10 minutes of latency; batch jobs and agent sessions can overshoot |
Same for auto-reload: Anthropic's key best practices treat auto-reload limits as a safeguard against leaked keys, and Google's Prepay plan has a monthly auto-charge limit. Uncapped auto-reload is an uncapped card.
For agents you build yourself, add a cap in code too. In Claient, when an account uses the platform's key, the webhook reserves budget atomically before each turn and stops replying when the monthly cap is hit. I described the same kill-switch idea in keeping Claude's token bill from ruining your month, and how to set caps for coding agents in Claude Code cost per month.
Keys stay on the server
OpenAI and Google both say it: no keys in browser or mobile code, route calls through your backend. In Next.js the line is the NEXT_PUBLIC_ prefix. Next.js inlines those values into the JavaScript bundle at build time, so an LLM key with that prefix is a published key.
// lib/llm.ts
import 'server-only'; // importing this from a Client Component fails the build
import Anthropic from '@anthropic-ai/sdk';
export const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
// app/api/chat/route.ts
import { anthropic } from '@/lib/llm';
export async function POST(req: Request) {
// Authenticate and rate-limit first: a public route that proxies
// your key is still your key.
const { message } = await req.json();
const res = await anthropic.messages.create({
model: MODEL, // whatever you pin in config
max_tokens: 512,
messages: [{ role: 'user', content: message }],
});
return Response.json(res.content);
}
That's the pattern in Claient: the platform's key is read from ANTHROPIC_API_KEY in the server-side engine config, and the only key with a NEXT_PUBLIC_ prefix is Supabase's anon key, which is meant to be public. More on that split in the Next.js + Supabase pre-launch security checklist and in shipping an AI product in a weekend.
If your backend has fixed egress IPs, restrict by IP too. OpenAI's IP allowlist works per organization or project for all API customers and rejects other IPs with a 401 ip_not_authorized, valid key or not. Google lets you restrict a key to IP addresses under Application restrictions in the Cloud console. Anthropic's help center lists IP allowlisting for Enterprise plans, set up through support.
Think twice before pasting a key into a hosted dashboard
Anthropic's help center has the most honest sentence on this: when you upload your API key to a third-party tool, "you are giving the developer of that tool access to your Claude Console account." That isn't a comment on OpenCode. It's how every hosted tool that calls a model with your key works, including the one I build. And deleting a key inside the tool doesn't revoke it. Only the provider can.
Claient accepts customers' own Claude keys (BYOK), so I'm on the other side of this. In its code the key goes into Supabase Vault and the settings table keeps only the secret's id. The function that returns the decrypted key can only be executed by the service_role the webhook uses, so no dashboard user, owner included, can read it back, and the UI never shows it again. If a customer's key gets revoked, the bot falls back to the platform key and notifies the business instead of going quiet. That limits what a dashboard bug can leak. It doesn't make a key unstealable from a compromised server; nothing does.
So on the customer side: give each hosted tool a dedicated key in its own project or workspace, with a low cap and an expiry, and ask the vendor where the key is stored, whether it's encrypted, and what can decrypt it.
Building an agent that holds customer API keys and want the storage, caps and fallbacks right from day one?
The first hour after a key leaks
- Kill it at the provider, not in the tool. OpenAI says to rotate immediately from the API keys page; in the Claude Console, Disable is reversible and Delete is permanent. If the key is being abused right now, revoke first and accept a few minutes of downtime. Create-then-revoke is for planned rotations.
- Issue the replacement properly. Right project or workspace, with an expiry, and deploy it everywhere the old one lived.
- Check usage per key back to the earliest date the key could have leaked, not just today.
- Lower the spend limit while you investigate.
- Find the leak, then fix it. Git history (deleting the file in a later commit doesn't remove it), CI and error logs, any tool you pasted it into.
- Contact billing support with the key ID, the dates and what happened. OpenAI's article points to help.openai.com.
FAQ
How do I secure my OpenAI API key?
Keep it on the server (environment variables or a secrets manager, never in client code or git), use one key per tool and project, create project keys with an expiration date, set a monthly spend limit with hard enforcement, and use IP allowlisting if your backend has fixed IPs. All of it is in OpenAI's key safety article as of October 2026.
How do I rotate an Anthropic API key?
Create a new key in the Claude Console with an expiration, deploy it everywhere the old one is used, confirm it works, then disable (reversible) or delete (permanent) the old key. Expiration is chosen at creation and can't be changed later.
Do spend alerts protect me if my API key leaks?
No. An alert tells you money is being spent; it doesn't stop it. Use hard caps: OpenAI spend limits with hard enforcement, Anthropic workspace spend limits, Google AI Studio project spend caps. None are instant, but a cap turns an open-ended bill into a bounded one.
Is it safe to paste my API key into a third-party tool?
Only if you'd trust that vendor with your provider account, because that's what you're giving them. If you do, give the tool its own key in its own project or workspace, with a low cap and an expiry. Deleting the key inside the tool doesn't revoke it; only the provider can.
None of this is exciting, which is the point: the boring setup is what keeps a breach somebody else's headline instead of your invoice. If you want an AI product built that way from the start, here's how I work.
Originally published on joancomadran.dev. I'm Joan, an AI engineer in Barcelona — work with me.
Top comments (0)