Guide Supabase

Someone told me my Supabase key is exposed. What now?

Short answer

It depends on which key. The publishable key (it starts with sb_publishable_) and the older anon key are meant to be public, so seeing them in your app is normal. Your data is safe only if your database rules (Row Level Security, or RLS) are right. If the key starts with sb_secret_ or is the older service_role key, treat it as leaked: fix how it got there, make a new key, and turn the old one off. Turning it off is what stops it.

Step 1: Find out which key it is

Ask the person who warned you where they saw it and what its first characters are. Don't ask them to send the full key. Then compare it with the keys in your Supabase project, under Settings, then API Keys.

What it starts withWhat it isIs it OK in your app?
sb_publishable_Publishable keyYes. "Anyone can read it, so it only reaches what Row Level Security allows."
eyJ, listed as anonOlder (legacy) anon keyYes, it's also meant to be public
sb_secret_Secret keyNo. "It bypasses Row Level Security, so it must never leave your control."
eyJ, listed as service_roleOlder (legacy) service_role keyNo. It also bypasses RLS

Both older keys start with eyJ, so check which one it matches in the dashboard.

Step 2a: If it's the publishable or anon key

Nothing leaked. Next, check that your RLS rules protect your data:

  1. Open your project's Security Advisor and fix every error. Its "RLS Disabled in Public" error flags tables with RLS off that signed-out or signed-in users can read through the API.
  2. Test with two test accounts. Create a private row as user A, then ask for it with user B's access token. With RLS working you get an empty list, []. Step-by-step: Is my Lovable app safe to launch?
  3. Don't test in Supabase's SQL editor. By default it runs as the postgres role, which "bypasses Row Level Security".

Step 2b: If it's a secret or service_role key

Supabase warns: "A secret key bypasses every Row Level Security policy you have. Never put one in a browser, a shipped application, or source control." Its order for a leaked key:

  1. "Don't rush. Fix the root cause of the leak before you rotate anything." Move the key out of your app's code so only server-side code uses it. In Lovable with your own Supabase project, secrets are stored in your Supabase project, where your edge functions can read them.
  2. Create a new secret key under Settings, then API Keys.
  3. Replace the old key everywhere it's used. If the leaked key is the legacy service_role key, also move your app from the legacy anon key to the publishable key now, because step 5 turns off both legacy keys.
  4. Confirm everything works with the new key.
  5. Turn the old key off. Making a new key doesn't do that: Supabase says legacy keys "stay valid until you disable them". Delete an old secret key (this can't be undone). For a legacy service_role key, deactivate the legacy keys (this can be reversed). That also turns off the legacy anon key, which is why step 3 moves your app to the publishable key first.

Deleting the key from your code isn't enough. Copies stay in your repo's history, in clones and in builds people already downloaded. Turning the old key off is what makes those copies useless. An sb_secret_ key is refused when it's sent from a browser, "but an attacker can still use the key from other tools." Supabase lists that browser block as one of the extra protections the new secret keys have and the old service_role key doesn't.

Then check your RLS too (Step 2a), so the fix covers both problems. The full walkthrough is in Supabase secret key exposed in your app?

Where we can help

  • Instant check (free, no signup): paste your URL at patchandship.com/check.html. It shows the result on screen in a few seconds. It reads your homepage only, follows up to 3 redirects, loads up to 10 of your site's own JavaScript files (never third-party scripts) and runs 5 security header checks. It looks for secret key patterns in that code and marks a Supabase public key as normal. A key that lives somewhere else, like your repo, won't show up, and the check never logs in or touches your database. Critical and High details stay hidden until you prove you control the site with a one-time code in a .well-known file, a homepage meta tag or a DNS TXT record. Email is never accepted as proof. It doesn't store your results, page contents or any key it finds. It keeps a short log entry for up to 1 day and a hashed copy of your IP address for up to 24 hours.
  • Emailed mini check (free, for app owners, or someone the owner has authorized): ask for one. We run it by hand and email you a one-page summary within 24 hours. It's passive and runs no database queries.
  • Security Fix, $149: every critical issue on our checklist fixed within 48 hours of working access. For an exposed secret key, "fixed" means we remove it from your code in the change we deliver. You rotate the key, and we tell you exactly which keys and settings to change. The checklist also covers RLS disabled or misconfigured and public storage buckets holding private files.
  • Fix & Deploy, $249: fixed and live on your host within 48 hours.

Otherwise, a full refund if you ask within 14 days of purchase. Rotating a key is a step only you can take, so it isn't part of the 48 hours. "Critical" and "live" are defined in our Refund Policy.

AI agents run the checks and a human engineer approves every change. It's not a penetration test, a security guarantee or a compliance certification. Details: Secure your Lovable app or Secure your Bolt app.

FAQ

How do I tell the anon key from the service_role key?

Both older keys are long keys that start with eyJ, so the start alone won't tell you. Check which one it matches in your Supabase project, under Settings, then API Keys. If it matches service_role, follow Step 2b.

Does making a new key stop the old one?

No. Supabase says legacy keys "stay valid until you disable them". Turning the old key off (Step 2b, step 5) is what stops it.

Should I switch from the anon key to the publishable key?

Yes. Supabase says it "is deprecating the anon and service_role keys by the end of 2026" and says to "Use the publishable (sb_publishable_xxx) and secret (sb_secret_xxx) keys instead." If you deactivate the legacy keys after a leak, move your app to the publishable key first.

Can a free check find a leaked key?

Our instant check looks for secret key patterns in your homepage and up to 10 of its own JavaScript files. It can't see your repo, its history or your database.

Sources