Supabase is the most common backend behind AI-built apps, and its security model is easy to describe and easy to get wrong. Here is what actually protects your data.
The anon key is public on purpose
The anon key ships to the browser by design. It identifies your project, it does not authorize anything on its own, and it is safe to expose only because Row Level Security is supposed to be the gate. If a table has no rules, the anon key is a master key for it.
- Never treat the anon key as a secret, and never assume its presence means data is exposed.
- Never ship the service_role key to the browser. It bypasses Row Level Security entirely.
- If service_role has ever been in a client bundle, rotate it and re-check every table.
Storage buckets have their own rules
Files live in buckets with their own access policies, separate from your tables. A bucket left public serves every file to anyone with the URL, and URLs get shared.
- Private by default, with explicit policies for who may read or write each path.
- Serve private files through signed URLs with a short expiry.
- Watch for user-identifying file names in public buckets, which quietly leak who your customers are.
Auth settings worth checking
- Email confirmation before an account can be used, if accounts matter.
- Sensible session lifetimes, and refresh tokens that cannot be replayed forever.
- Rate limits on sign-in and password reset.
- Multi-factor authentication available, at least for anyone with admin access.
- Third-party sign-in reviewed: which providers are actually enabled, and who they let in.
The REST API exposes your tables
Every table is served through an autogenerated API. That is convenient, and it means a table's name plus the anon key is all a stranger needs to try reading it. The rules are the only thing between your data and the open internet.
- Confirm the API does not expose tables you thought were internal.
- Test by fetching a table with the anon key and no session. It should return nothing.
- Watch for views and functions that run with elevated privileges but are callable by the public.
A Supabase pre-launch pass
- 01
List every table
For each one, confirm RLS is on and there is at least one policy per operation.
- 02
Read your data as a stranger
With the anon key and no session, try to read a private table. Anything returned is a leak.
- 03
Try to read another user's row
Sign in as one user and attempt to fetch a row that belongs to another.
- 04
Audit the buckets
Check which buckets are public and what they hold.
- 05
Confirm the keys
Make sure only the anon key is in the browser and service_role is server-only.
- 06
Run an external review
A black-box pass over the running app checks exposed endpoints, keys and headers alongside the rest of your launch list.
The short version
With Supabase, the anon key is not the risk. A table without rules is.