Guide
Is my Supabase key leaked? Anon key vs service_role key, explained
Check your live app first. Paste your app's public link into the free MondayMedic check. It reads only public pages and scripts, takes about a minute, needs no account, and flags a secret key in the browser or tables the public key can read. It does not log in or change data, and it is not a full security audit.
The short answer
- Anon / publishable key in the browser: normal. Supabase designs it to be public.
- service_role key or an
sb_secret_...key in the browser: a real leak. It skips every Row Level Security (RLS) rule. Rotate it now. - Anon key that can read private tables: the key isn't the problem; your RLS is. Fix the table rules, not the key.
How to tell which key you're looking at (one minute)
- Open your live app, view source or DevTools > Sources, and search for
eyJ,sb_secret,sb_publishableandservice_role. - Legacy keys are JWTs (three parts split by dots, starting
eyJ). Decode the middle part (any JWT decoder, oratobin the console) and read therolefield:anonis the public key,service_roleis the secret one. - Newer keys say what they are in the prefix:
sb_publishable_is fine in the browser,sb_secret_never is. - Also check env var names. Anything starting with
VITE_orNEXT_PUBLIC_gets baked into the browser bundle, so a secret key stored under one of those names is public.
If you found the service_role or sb_secret key
Do these in order. Rotate before you touch code, because the old key keeps working until you delete it.
- In Supabase, open Settings > API Keys and create a new secret key.
- Put the new key wherever it legitimately lives (Edge Functions, server, CI) and redeploy.
- Delete or roll the old key.
- Make sure the browser client only uses the anon/publishable key.
- Turn RLS on for every public table and add owner-only policies (see our RLS guide).
- Check your logs for writes you didn't make during the time the key was public.
If you only found the anon key
Don't rotate it. A new anon key is just as visible. Instead, test whether it can read things it shouldn't: log out and query each table with the anon key. If private rows come back, RLS is off or a policy is too open (for example using (true)). See the RLS guide for fixes.
Why AI builders hit this
Tools like Lovable, Bolt and Cursor wire the browser straight to Supabase. When a feature needs "admin" access, an assistant may reach for the service_role key and put it where the frontend can read it, or a key pasted into a chat ends up in code. It works, so nothing looks wrong.
FAQ
Is the Supabase anon key a secret?
No. It's meant to be in the browser. RLS is what protects data.
Can I hide the anon key behind env vars?
Env vars with VITE_/NEXT_PUBLIC_ still end up in the bundle. That's fine for the anon key and never fine for a secret key.
Does MondayMedic call the anon key a leak?
No. The free check flags secret keys and tables that answer the public key.
How do I keep it from coming back?
Re-check after every new feature. The paid Monday checkup emails you new public issues each week.