An sk-ant- key in a public repo is a company card taped to a lamppost. Take a breath. This runbook gets the key revoked, the damage checked, and the mess cleaned up in about 10 minutes. Then we make sure it's the last time.
Five steps, in this exact order. The order matters: the key dies first, the git cleanup comes last. One quick triage question before you start: is the key in a public repo or a deployed site? Then do step 1 in the next few minutes, not tonight. If it only ever sat in a private repo, you still do everything below, just without the racing heart.
Kill the leaked key in the Claude Console and ship a new one. About 2 minutes.
Read your usage logs for activity that isn't yours, and know what to do about surprise spend.
Keys leak in packs. Everything that lived next to the sk-ant- key needs rotating too.
Clean the repo after the key is dead. Scrubbing alone fixes nothing, and we'll explain why.
What GitHub and Anthropic catch automatically, and the gaps that stay your problem.
One thing that makes this easy: Anthropic key rotation is two moves. You create a new key, and you delete the old one. There is no single "rotate" button, and you don't need one.
Go to the API keys page in the Claude Console: platform.claude.com/settings/keys. (Older console.anthropic.com links redirect to the same place.) Find the key that matches the leaked prefix.
If your app is live in production, create the replacement first so you can swap with almost no downtime:
.env as ANTHROPIC_API_KEY, your CI secrets, and your host's environment variables (Vercel, Netlify, wherever you deploy). Redeploy.If nothing is running in production, flip the order: delete the leaked key first, then create the new one at your own pace.
Finally, confirm the old key is actually dead. From a terminal:
curl https://api.anthropic.com/v1/models \
-H "x-api-key: PASTE_THE_OLD_KEY_HERE" \
-H "anthropic-version: 2023-06-01"
You want a 401 back, with an authentication_error in the body. 401 is the "this key doesn't work anymore" error. It's the sound of the door locking.
Missed an environment? That's the classic follow-up failure. Check local .env files, CI secrets, serverless function configs, and every deploy target. A forgotten copy of the new key means your app breaks at 2am; a forgotten copy of the old key means the leak never really closed.
Open the usage page in the Claude Console (platform.claude.com/usage) and read the last 7 days. You're looking for anything that isn't you: spikes at hours you weren't working, models you never call, token volume that doesn't match your app's traffic.
Be honest with yourself about the timeline. If the key sat in a public repo for more than a day, assume someone found it. Automated scrapers hunt fresh public commits for key patterns around the clock. "Nobody saw my repo" is not a plan.
If you find spend you don't recognize:
One habit that shrinks the next blast radius: Anthropic's console supports workspaces, which let you segment API keys and control spend per use case. A separate key per environment, each in its own workspace, means a leaked dev key can't quietly drain your production budget.
Here's the uncomfortable part. An sk-ant- key almost never leaks alone. It leaks because a .env file got committed, and that file usually holds the whole family: a database URL, a Stripe key, an OpenAI key, a Supabase service role key, session secrets.
If the Anthropic key was exposed, everything next to it was exposed. Each of those is its own small incident, and each gets rotated at its own provider's console. Work in this order:
The moves are the same everywhere: open the API keys page in the provider's console, create a replacement, update your environments, kill the old credential, then confirm the old one fails. We keep a general runbook for this at what to do when any API key leaks, with the same calm-ordered approach as this page.
A lot of people do this step first, feel better, and stop. That's the trap this page exists to prevent.
Deleting the file in a new commit does nothing. The old commit still contains the key, and anyone can read old commits.
Rewriting history helps less than it feels like it does. Tools like git filter-repo or the BFG can rewrite your repo so the key never appears, and a force-push replaces what's on GitHub. But git is a copying machine. Forks, clones, and anything a scraper already downloaded keep the old history. You cannot un-publish a secret. That's why the key dies at the provider in step 1, and the repo cleanup is hygiene, not the fix. Scrubbing alone is theater.
It's still worth doing, for two honest reasons: future clones of your repo stay clean, and nobody re-leaks the key by referencing an old commit. While you're in there, check whether any env file ever touched history:
git log --all -p -- .env .env.local .env.production | head
If any .env file shows up in history at all, every key that was ever inside it needs the step 1 treatment. Git history doesn't forget.
Then make the same mistake impossible to repeat:
echo ".env" >> .gitignore
echo ".env.local" >> .gitignore
echo ".env.production" >> .gitignore
echo "!.env.example" >> .gitignore
There is a real safety net here, and it's worth understanding exactly where its edges are.
GitHub's secret scanning runs automatically, for free, on public repositories, and it knows the Anthropic key patterns. Anthropic is an official GitHub secret scanning partner. In GitHub's own words: exposed tokens found in public repositories are forwarded to Anthropic, "who will then revoke the compromised tokens and notify the affected users." GitHub also offers push protection, which can block a commit containing a known key pattern before it ever lands.
That net covers public GitHub repos. It does not cover a private repo without scanning enabled, a key baked into your frontend JavaScript bundle, a screenshot, a log file, or a paste in a chat channel. It doesn't refund the spend that happened before revocation. It doesn't rotate the database URL sitting next to the key in your .env. And when a key is auto-revoked, your app starts failing until you ship a replacement, so you're doing steps 1 through 4 anyway.
Think of the automatic net as a smoke alarm, not a sprinkler system. It's genuinely good that it exists. It also goes off after the smoke.
If an sk-ant- key ended up in your repo, it happened somewhere between "it works locally" and git push. That moment is exactly where a pre-ship check belongs, and you already work in the tool that can run one. Lictor is a free, open-source security plugin for Claude Code. Two commands:
/plugin marketplace add Raffa-jarrl/Lictor-AI
/plugin install lictor-security-suite@lictor-ai
It audits your codebase against a 48-check catalog and reports in plain English. Leaked AI-provider keys (OpenAI, Anthropic, Gemini) is check #2 on the list. Nothing is a black box; you can read every check before you run it.
We publish a benchmark: a blind run on a 30-case stratified sample of OWASP Benchmark 1.2 scored an F1 of 93.8%. The honest caveat, stated there too: that's a 30-case, injection-focused sample, not the full benchmark. The number is real and reproducible, and we won't pretend it's bigger than it is.
Lictor is built by a security engineer with 20 years in the field who does real responsible-disclosure work. The checks come from what actually leaks in the wild, not from a compliance checklist.
Teams that want this watched continuously rather than run by hand can look at continuous monitoring from $49/mo.
The repo is one leak surface. Your deployed site is another. Point our free scanner at it: passive, quick, no signup. If something obvious is exposed, you'll know before someone else does.
Run the free scan →Anyone who finds it can call the Claude API as you, which means spending your credits and running up your bill. If the key was pushed to a public GitHub repo, GitHub's secret scanning forwards exposed Anthropic keys to Anthropic, which revokes compromised keys and notifies you. Don't wait for that. Revoke it yourself, check usage for activity that isn't yours, and rotate whatever leaked alongside it. Keys leak in packs.
Sometimes, through one channel. Anthropic is a GitHub secret scanning partner, so keys found in public GitHub repositories get forwarded to Anthropic, which revokes them and notifies the affected user. That covers public GitHub only. A key leaked in an unscanned private repo, a frontend bundle, a screenshot, or a chat message has no one coming for it, and no auto-revocation undoes spend that already happened. Treat it as a backstop, not a plan.
Open the API keys page in the Claude Console. Create the new key first and copy it right away (it's shown once). Update every environment: local .env, CI secrets, deployed host. Delete the leaked key. Then call the API with the old key and confirm you get a 401 authentication error back. About 10 minutes, start to finish.