Example finding How it works Coverage PENTEST METHODOLOGY DOCS PRICING FAQ MCP CONTACT LOG IN SIGN UP →

Supabase anon key: what it can access

The Supabase anon key is meant to be public, and exposing it is safe only if every table is protected by Row Level Security (RLS). It ships in every browser bundle that talks to Supabase. Policies and database grants protect your data, not the key. If a table in an exposed schema has RLS disabled, anyone holding the anon key can read and write it.

What is the Supabase anon key?

The anon key is a legacy API key, a JWT signed by your project with the role anon. Supabase’s newer equivalent is the publishable key, sb_publishable_.... Both identify your app to the API and let requests run as the anon role until a user signs in. See the Supabase API-key guide.

Key Where it belongs What protects your data
Legacy anon key Browser, mobile app RLS policies and grants
Publishable key, sb_publishable_... Browser, mobile app RLS policies and grants
Legacy service_role key Backend only Nothing: it bypasses RLS
Secret key, sb_secret_... Backend only Nothing: it bypasses RLS

What can someone do with my anon key?

Anything the anon role is allowed to do. In practice that means:

  1. Read and write tables without RLS. The Data API exposes tables in the public schema by default. RLS disabled means no row filter at all.
  2. Read tables with permissive policies. A policy of using (true) grants every row to every caller it applies to.
  3. Sign up. If email signup is enabled, anyone can create an account and get the authenticated role. A policy written to authenticated using (true) is then effectively public.
  4. Call database functions in exposed schemas that the role has EXECUTE on, including security definer functions that run with their owner’s rights.
  5. List and download files from public storage buckets, or from private buckets whose storage policies allow anon.

Our anon-key honeypot study records what callers did with a deliberately exposed key.

How to test what your anon key can reach

Use the key your deployed frontend ships, not a privileged one. Request one row from each table:

curl "https://<project-ref>.supabase.co/rest/v1/<table>?select=*&limit=1" \
  -H "apikey: <anon-key>" \
  -H "Authorization: Bearer <anon-key>"

A JSON row means anonymous callers can read that table. An empty array [] means RLS filtered every row, or the table is empty. A permission error means the role has no grant on it.

Then repeat the request signed in as an ordinary test user, and try POST, PATCH and DELETE against rows that belong to a second test user. The Supabase RLS checker runs these checks against a deployed app.

Supabase’s Security Advisor in the dashboard also flags tables in exposed schemas with RLS disabled.

Should I rotate a leaked anon key?

Rotating the anon key does not fix an exposure. The key was public before and the replacement will be public too. If someone reached data they should not have, the fix is the policy that let them, not the key.

Rotate only if the value you exposed was actually the service_role or a secret key. The service-role exposure walkthrough covers that case.

Fix checklist

  1. Enable RLS on every table in an exposed schema.
  2. Replace using (true) policies with checks on auth.uid() or a membership table.
  3. Disable signup if the app has a fixed set of users.
  4. Revoke EXECUTE from public and anon on functions the browser does not need. Postgres grants it to public by default, so revoking from anon alone changes nothing.
  5. Make storage buckets private unless the files are meant for anyone.

The Supabase RLS guide shows policy patterns for each case, and the Supabase hardening guide covers the rest of the project configuration.

Reviewed against the Supabase docs on October 9, 2026.

See what your anon key can reach

We call your Supabase project with the key your frontend already ships and report every table, bucket and function it can touch.

14-day free trial · No credit card · Cancel anytime

SCAN YOUR APP →