Found your Supabase secret key in the browser? What to do in the first hour
A service role or secret key in your frontend gives anyone full access to your database. What to do, in order: revoke, replace, check the logs, fix the cause.
5 min read
You searched your app’s JavaScript for service_role or sb_secret_, as in our 10-minute Supabase check, and found a match. Or someone emailed to say they found it. Either way, the key that ignores every security rule in your database is public.
This is the most serious mistake an AI-built app can ship with, and it is also one of the most common. The good news: the fix takes about an hour if you do it in the right order.
Why this key is different
Supabase gives every project two kinds of keys:
| Key | Where it belongs | What it can do |
|---|---|---|
Publishable key (sb_publishable_…) or legacy anon key |
The browser | Only what your Row Level Security rules allow |
Secret key (sb_secret_…) or legacy service_role key |
A server only | Everything: it bypasses Row Level Security entirely |
With the secret key, a stranger does not need to find a gap in your rules. They can read every table, change any row, delete data and download files from private storage. Your rules simply don’t apply to them.
Minute 0–10: find out which key leaked
Open Project Settings → API Keys in the Supabase dashboard and compare with what you found in the browser:
- If it starts with
sb_secret_, it is one of the new secret keys. You can replace it on its own, without touching anything else. - If it is a long token starting with
eyJ, it is the legacy service_role key. Legacy keys can’t be rotated one at a time, so the path is different (below).
Also note where the key was used: which file, which feature. AI tools usually put it in the frontend because something failed with the public key, typically a missing RLS rule, and the quick way around it was the key that ignores RLS.
Minute 10–30: replace the key
If it is a new secret key (sb_secret_)
- In API Keys, create a new secret key and give it a name that says where it will be used (for example
edge-functions). - Put the new key wherever server code needs it: Edge Function secrets, your hosting provider’s environment variables, background jobs.
- Delete the leaked key. Requests that use it start failing at once.
If it is the legacy service_role key
- Create a publishable key and a secret key in the API Keys page, if you don’t have them yet.
- Switch your frontend from the anon key to the publishable key, and your server code from service_role to the secret key. Deploy.
- Deactivate the legacy API keys in the same page. This turns off both the anon and the service_role keys, which is why step 2 comes first. Supabase lets you re-activate them if you missed a client, so this step is reversible.
Supabase is phasing out the legacy keys anyway, so this is work you would have to do soon regardless.
Minute 30–45: remove the key from the frontend for good
Replacing the key stops the bleeding; the code that needed it will now break. Don’t fix that by putting the new secret key back in the browser. Move the work to the server:
- A Supabase Edge Function for the action that needed elevated access (sending an invite, writing to an admin table, calling a paid API). Edge Functions can read the project’s secret keys from their environment without you pasting them into code.
- Or an RLS rule that allows exactly what the screen needs. Often the reason the AI reached for the secret key was a table with RLS on and no rule for the signed-in user. The right rule makes the secret key unnecessary.
Then search the built JavaScript again for sb_secret_, service_role and the first characters of your new key. Zero matches is the goal.
Minute 45–60: check what happened while it was exposed
You need to know whether anyone used the key, and for that you need logs while they still exist.
- In the dashboard’s Logs, look at API requests over the exposure window: unusual volumes, requests to tables your app never reads, bulk
select=*downloads, deletes you didn’t make. - Look at Auth → Users for accounts you don’t recognize, and at storage for files you didn’t upload.
- If you suspect changes to your data, check what backups or point-in-time recovery your plan includes before you change anything else.
Log retention on Supabase depends on the plan and can be short, so do this today, not next week.
Make sure it doesn’t come back
AI tools repeat what they have seen in your project. A few habits prevent a second leak:
- Keep secret keys only in server-side environment variables, never in variables your framework sends to the browser (in Vite, anything starting with
VITE_ends up in the bundle; in Next.js, anything starting withNEXT_PUBLIC_). - Use one secret key per service, named after it, so a leak forces only one replacement.
- Before each release, search the build output for
sb_secret_andservice_role. It takes seconds. - When the AI suggests the secret key to make an error go away, treat that as a sign that an RLS rule is missing.
If you would rather have someone check the whole app, keys, rules, storage and authentication, our free Security Check looks at it from the outside, read-only, and tells you what to fix first.
SupabaseAPI keysAI-built apps
Keep reading
All articles
App security
Is your AI-built app leaking data? A 10-minute Supabase check
Apps built with Lovable or Bolt on Supabase often go live with tables anyone can read. How to check yours in ten minutes, and what to fix first.
3 min read

Websites
Why your contact form emails land in spam (and how SPF, DKIM and DMARC fix it)
Messages from your website form go to spam or never arrive? Usually it is how they are sent, not what they say. What to check and the three DNS records to fix.
4 min read