Skip to content

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_)

  1. In API Keys, create a new secret key and give it a name that says where it will be used (for example edge-functions).
  2. Put the new key wherever server code needs it: Edge Function secrets, your hosting provider’s environment variables, background jobs.
  3. Delete the leaked key. Requests that use it start failing at once.

If it is the legacy service_role key

  1. Create a publishable key and a secret key in the API Keys page, if you don’t have them yet.
  2. Switch your frontend from the anon key to the publishable key, and your server code from service_role to the secret key. Deploy.
  3. 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 with NEXT_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_ and service_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

This article is also available in: PortuguêsEspañol日本語中文

All articles