Critical severity · Supabase

Exposed Supabase service key on Supabase

A Supabase service role key is in your client-side JavaScript. This key bypasses Row Level Security — anyone who extracts it from your bundle has full read and write access to your entire database. The fix: rotate the key immediately in Supabase dashboard, remove every reference to it from client code, and only use it from server-side code (API routes, server components, serverless functions).

The fix for Supabase

Supabase dashboard

Rotate the key: Settings → API → Reset service_role key. This invalidates the leaked one.

Why it matters

Supabase has two keys. The anon key is safe to expose — it works with RLS. The service role key is admin. The naming is confusing and AI tools sometimes use the service role key everywhere. Once it is in your client bundle, it is game over for your database.

Confirm the fix worked

Scan your Supabase site to confirm this finding is gone.

AI prompt

Apply across your codebase

Paste this into Cursor, Lovable, Bolt, v0, or Claude Code.

My Supabase service role key is in my client-side JavaScript. First, rotate the key in Supabase dashboard. Then search my codebase for every use of the service role key and determine which ones are legitimately server-side (API routes, server actions, backend functions) and which are wrongly in client code. For client usage, replace with the anon key + proper RLS policies. For server usage, make sure the key is only in a server-only file and the env var does not have a NEXT_PUBLIC_ prefix.

FAQ

Frequently asked questions

I'm not sure which key is which.
Decode the JWT at jwt.io. Look at the `role` claim. `service_role` is the admin key. `anon` is the safe-to-expose one.
What does the anon key look like in my code?
The anon key is a JWT starting with `eyJ...`. Its role claim is `anon`. It is safe to include in client code *if* you have RLS enabled on every table.