Critical severity · Supabase

Supabase RLS disabled on Supabase

One of your Supabase tables has Row Level Security turned off. The anon key is in your client-side code, which means anyone who views your site source can read — and possibly write — every row. This is the single most common critical finding in AI-built apps. Fix it by enabling RLS on every table, then writing policies that match how your app actually uses the data. Never ship a Supabase app with RLS off on a user-facing table.

The fix for Supabase

Supabase SQL

Enable RLS on every public table, then add policies. Example for a `posts` table with a `user_id` column:

-- Turn on RLS
alter table public.posts enable row level security;

-- Allow users to read their own rows
create policy "users read own posts"
  on public.posts for select
  using (auth.uid() = user_id);

-- Allow users to insert rows as themselves
create policy "users insert own posts"
  on public.posts for insert
  with check (auth.uid() = user_id);

-- Allow users to update/delete their own rows
create policy "users update own posts"
  on public.posts for update
  using (auth.uid() = user_id);
create policy "users delete own posts"
  on public.posts for delete
  using (auth.uid() = user_id);

Public-read tables

If the table is meant to be public (like a blog posts list), you still need RLS on and a permissive read policy.

alter table public.posts enable row level security;
create policy "anyone can read posts"
  on public.posts for select
  using (true);
-- No insert/update/delete policy means those are blocked for anon.

Why it matters

Supabase exposes your database over HTTP using the anon key. That key is meant to be public — RLS is what keeps your data safe. With RLS off, the anon key is equivalent to full database access.

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 project has a table where Row Level Security is disabled. First, list every table in the public schema and tell me which ones have RLS off. For each one: determine from my codebase which users should be able to read, insert, update, and delete rows (look at my fetch calls, check if there is a user_id or owner_id column, check if it is public data like blog posts). Then write the `alter table ... enable row level security;` and matching `create policy` statements. Make policies as restrictive as possible while still letting my app work.

FAQ

Frequently asked questions

Should I disable RLS for faster development?
No. Write the policies as you build. Every AI-built app I have seen with RLS off in production had someone pull data they should not have. Turn it on from the start and write policies as you add tables.
Do I need RLS if I only use the service role key?
The service role key bypasses RLS by design. If your app only ever queries through your own backend using the service role key, you can keep RLS off. But you must be sure the service role key never touches the client — and most AI-built apps use the anon key directly from the browser, which requires RLS.
How do I test my RLS policies?
In the Supabase SQL editor, impersonate a user with `set local role authenticated; set local request.jwt.claim.sub = 'USER_ID';` and try your queries. Or use the `supabase-js` client from a test script with a real user's JWT.