Guides / Leaked key response

Leaked a secret API key? What to do in the first hour

You pushed a key to a public repo, shipped it in your frontend, or pasted it somewhere you shouldn’t have. It happens to experienced developers too. Here’s what to do, in order, so the leak costs you an hour rather than your users’ data or a big bill.

Get your app checked by hand

First: is it actually a secret?

Some keys are meant to be public, and finding them in your frontend is normal:

  • Supabase publishable key (sb_publishable_…) or legacy anon key
  • Stripe publishable key (pk_live_… / pk_test_…)
  • Firebase apiKey in your web config

Those are protected by your database rules, not by secrecy. If one of those is what you found, check your Supabase RLS or Firebase rules instead.

These are secrets, and a leak is an emergency:

  • Supabase secret key (sb_secret_…) or legacy service_role key. These bypass all row-level security, so a leak exposes your whole database.
  • OpenAI, Anthropic, Gemini and other AI provider keys (OpenAI keys start with sk-)
  • Stripe secret or restricted keys (sk_live_…, rk_live_…)
  • Firebase / Google Cloud service account private keys (a JSON file containing "private_key")
  • Database passwords and connection strings

The five steps, in order

  1. Rotate the key, fast. Deleting the file, deleting the commit or making the repo private does not un-leak a key. Automated bots scan public repositories for keys, so assume it’s already been copied. If you can see it being abused, revoke it right now, even if your app breaks for a while. Otherwise, make sure the new key won’t leak the same way (step 4) as you swap it in.
  2. Find everywhere it leaked. Your frontend bundle, your git history, other repos, screenshots, chat messages, AI chat histories, deploy logs.
  3. Check for misuse. Look at usage, logs and billing for the time since the leak (details per provider below).
  4. Fix the cause. Move the key to a server-side secret so the same mistake can’t happen on your next deploy. See how to keep keys out of your frontend.
  5. Prevent the next one. Make sure .env is in .gitignore, and turn on GitHub secret scanning and push protection for your repositories.

Supabase secret or service_role key

Supabase’s guidance is to fix the cause of the leak first, then rotate. If you can see the key being actively abused, retire it immediately, even though parts of your app will break until you’ve swapped in a new key.

For a leaked secret key (sb_secret_…):

  1. In Settings → API Keys, create a new secret key.
  2. Replace the leaked key everywhere it’s used: your server, Edge Functions, webhooks and scheduled jobs.
  3. Confirm everything works with the new key.
  4. Delete the compromised key in Settings → API Keys. This can’t be undone, and the old key stops working.

For a leaked legacy service_role key, there’s a catch: creating new keys doesn’t revoke the old ones, and deactivating the legacy keys turns off both service_role and anon. So:

  1. Create a new secret key and replace the service_role key in all server-side code.
  2. Replace the legacy anon key in your frontend and mobile apps with a publishable key, and deploy.
  3. Confirm everything works, then deactivate the legacy keys in Settings → API Keys. Don’t re-enable them later, since that restores the leaked key.
  4. Revoke the legacy JWT secret by following Supabase’s JWT signing keys guide. Legacy keys are signed with that secret, so anything that still trusts it can accept the leaked key. Read that guide’s notes on the effect on signed-in users before you do this in production.

Then review your project’s logs and data for unexpected reads, changes or deletions since the leak. Because these keys bypass RLS, assume any table could have been read.

OpenAI and other AI provider keys

  1. In your provider’s dashboard, open the API keys page, create a new key and put it in your server-side environment.
  2. Delete (revoke) the leaked key.
  3. Check the usage and billing pages for spikes since the leak. If you see usage you don’t recognize, contact the provider’s support.
  4. Set a monthly budget or usage limit with alerts, so the next problem shows up as an email.

Stripe secret key

  1. In the Stripe Dashboard, go to Developers → API keys and roll (regenerate) the secret key. Update your server with the new key.
  2. Review recent activity in the Dashboard (payments, refunds, payouts, customers and the request logs) for anything you didn’t do.
  3. If you see unauthorized activity, contact Stripe support right away.
  4. For future integrations, consider restricted keys that only have the permissions each part of your app needs.

Firebase service account key

  1. In the Google Cloud console, go to IAM & Admin → Service accounts, open the service account, and delete the leaked key under Keys.
  2. If your server still needs one, create a new key and store it as a server-side secret. Inside Cloud Functions, the Admin SDK can get credentials automatically, so you may not need a key file at all.
  3. Review your Firestore, Realtime Database and Storage data, and your project’s audit logs, for changes since the leak. Admin credentials bypass your Security Rules.

A prompt to find every leaked secret in your code

Once you’ve rotated the key, use your AI coding tool to find where else secrets live, so you can move all of them in one pass.

Search this whole project, including config files and client-side env
vars, for secret credentials: Supabase secret or service_role keys,
OpenAI/Anthropic/Gemini API keys, Stripe secret or restricted keys,
Firebase service account JSON, database URLs and passwords.
For each one, tell me the file and line, whether it ends up in the
browser bundle, and how to move it to a server-side secret. Make sure
.env files are in .gitignore. Do not print the full secret values.

The short version

  • Rotate first. Deleting the commit or making the repo private doesn’t un-leak a key.
  • For Supabase legacy keys, move the frontend to a publishable key before deactivating them.
  • Check usage, logs and billing for the time since the leak.
  • Move every secret to the server, then turn on secret scanning and push protection.

Not sure what else is exposed? The Launch Check covers exposed keys, database rules, unprotected routes and AI features, with fixes you can paste into your coding tool.

Want a second pair of eyes?

Get your app checked before launch.

The Launch Check covers your database rules, exposed keys, unprotected routes and AI features by hand, with plain-English findings, fixes you can paste into your AI coding tool, and a recheck. $400, fixed price.