ShipReady Guide · Keys and secrets · OpenAI · Stripe · Supabase

How to Rotate a Leaked API Key (OpenAI, Stripe, Supabase)

Deleting a leaked key from your code doesn't make it safe. The old key keeps working until you revoke it at the provider, and copies live on in your deployed bundle, browser caches and git history. Here's how to rotate it properly, provider by provider.

7-minute readUpdated Oct 2026All guides

The short version

  • Order matters: create a new key, put it on your server, revoke the old one, then fix the code that leaked it.
  • Deleting code is not revoking. Bots scrape public repos and bundles within minutes, and the old key works until the provider kills it.
  • Check the damage: review usage and logs for the window the key was exposed.
  • Supabase legacy keys can't be revoked one at a time. Plan for the anon key changing too.

1. Why fixing the code isn't enough

Once a key has been served to a browser or pushed to a public repo, assume someone has it. Your redeploy removes it from the next version of your site, but:

  • Anyone who loaded the old bundle has the key in their cache or devtools.
  • Automated scrapers watch public GitHub pushes and npm packages for key patterns.
  • Git history keeps the key even after you delete it in a later commit.

The only thing that makes a leaked key harmless is revoking it at the provider.

2. The safe order of operations

1

Create a replacement key

Make the new key first so your app doesn't go down while you swap.

2

Put it somewhere private

Add it as a server-side environment variable or secret (Vercel, Netlify, Cloudflare, Supabase Edge Function secrets). Never with a NEXT_PUBLIC_ or VITE_ prefix.

3

Revoke the old key

Delete or roll it at the provider. This is the step that actually stops abuse.

4

Fix the leak and redeploy

Move the call that needed the key to a server route, then redeploy so the old pattern is gone.

5

Review usage

Look at the provider's usage, logs or events for the time the key was exposed.

3. OpenAI and other AI keys

In the OpenAI platform, open API keys, create a new secret key in the same project, update your server environment variable, then delete the leaked key from the list. Deleting it revokes it immediately.

Then open Usage and look for spikes you don't recognize during the exposure window. While you're there, set a monthly budget and an alert in your project's limits settings so a future leak has a ceiling.

Anthropic, Google AI Studio and most other AI providers work the same way: create, swap, delete, then review usage and set a spend limit.

4. Stripe secret, restricted and webhook keys

In the Stripe Dashboard, go to Developers, then API keys, and use Roll key on the leaked secret or restricted key. Stripe lets you choose when the old key expires; for a key that was public, choose to expire it now and update your server right after.

Then review Logs and Events in the Dashboard for API calls you didn't make, such as refunds, customer exports or new webhook endpoints.

A leaked webhook signing secret (whsec_) is rolled from that webhook endpoint's settings, not the API keys page. The publishable key (pk_) never needs rotating because it's public by design.

5. Supabase service role and secret keys

Supabase has two generations of API keys, and rotating works differently for each. Check Project Settings, then API Keys, to see which your project uses.

KeyPublic?If it leaked
sb_publishable_…YesFine to be public. RLS protects your data.
sb_secret_…NeverCreate a new secret key, update your server, then delete the leaked one.
anon (legacy JWT)YesFine to be public, as long as RLS is on.
service_role (legacy JWT)NeverCan't be revoked alone. Move to the newer secret keys and disable the legacy keys, or rotate the JWT secret, which also changes your anon key.

Plan for the legacy route. Changing the JWT secret invalidates both legacy keys, so your front end needs the new anon key in the same deploy, and signed-in users may need to log in again.

After rotating, check your tables for rows you didn't write, your Auth users list for unfamiliar accounts, and Storage for unexpected files. A service role key bypasses RLS, so anything was possible while it was out.

6. Everything else, and your git history

For email (Resend, SendGrid, Postmark), SMS (Twilio) and cloud keys (AWS access keys), the pattern is the same: create a replacement in the provider dashboard, swap it on your server, then delete or deactivate the old one and review usage.

If the key was committed to GitHub, GitHub's secret scanning may already have alerted you or the provider. Rewriting history to remove the commit is optional cleanup. It doesn't help if the key wasn't revoked, and it isn't needed once it has been.

Find secrets in your built output before deploying
# Next.js
grep -rnoE "sk_(live|test)_[A-Za-z0-9]+|sk-[A-Za-z0-9_-]{20,}|service_role|whsec_" .next/static

# Vite (Lovable, Bolt and most React apps)
grep -rnoE "sk_(live|test)_[A-Za-z0-9]+|sk-[A-Za-z0-9_-]{20,}|service_role|whsec_" dist

Before you ship

  • New key created and stored server-side, with no public prefix.
  • Old key revoked or rolled at the provider, not just removed from code.
  • The code path that leaked it now runs on a server.
  • Usage and logs reviewed for the time the key was exposed.
  • Budget caps and alerts set so the next mistake has a ceiling.

Check your live site in 60 seconds

ShipReady scans your deployed URL and the JavaScript visitors actually download: leaked keys, Supabase exposure, unprotected API routes, titles and share images. Secret findings unlock only after you verify you own the site.

Free scan, no signup, no code upload.

FAQ

It was only exposed for a few minutes. Do I still need to rotate?

Yes. Scrapers watching public repos and new deployments are fast, and you can't prove nobody copied it. Rotating takes five minutes; a drained account takes much longer to sort out.

Will rotating break my app?

Only if you revoke before swapping. Create the new key, deploy it, then revoke the old one, and there's no gap.

It was a test key. Does it matter?

A Stripe test key can't move real money, but rotate it anyway and fix the code. The same pattern will leak the live key at launch.

How do I know if the key was used?

Each provider shows usage: OpenAI's Usage page, Stripe's Logs and Events, Supabase's logs and table data. Look for activity you didn't cause during the exposure window.

Keep reading

Sources: Stripe: API keys · Supabase: Understanding API keys · GitHub: About secret scanning