Fix Supabase tables with no Row Level Security policies

If your Supabase tables do not have Row Level Security (RLS) enabled and configured, any user with your anon key can read, insert, update, or delete any row in those tables. AI code generators frequently create tables without RLS because it adds complexity, but this leaves your data completely unprotected in production.

Error messages you might see

Warning: RLS is disabled for table 'table_name' in Supabase dashboard
Supabase dashboard: 'RLS is not enabled on this table'
Any authenticated user can access all rows in the table
Anonymous users can query the table without restrictions

Why this happens in AI-generated code

1

AI-generated SQL does not enable RLS

AI tools generate CREATE TABLE statements without `ALTER TABLE ... ENABLE ROW LEVEL SECURITY`. The table works immediately, but with no access restrictions, which the AI treats as a feature because it avoids permission errors during development.

2

RLS enabled but no policies created

Some AI tools enable RLS on the table but forget to create any policies. With RLS on and no policies, the table becomes completely inaccessible (all queries return empty), which is safe but non-functional. The developer then disables RLS to fix it, removing all protection.

3

Using service role key instead of anon key on the client

AI-generated code sometimes uses the service_role key in the browser client to bypass RLS entirely. This gives full database access to anyone who inspects the JavaScript bundle, which is worse than having no RLS at all.

How to fix it

1

Enable RLS and create policies for each table

For every table that stores user data, run `ALTER TABLE "your_table" ENABLE ROW LEVEL SECURITY;` then create policies for each operation. A basic pattern: `CREATE POLICY "Users can view own data" ON "your_table" FOR SELECT TO authenticated USING ((select auth.uid()) = user_id);`. Repeat for INSERT (with WITH CHECK), UPDATE, and DELETE.

2

Check which tables are unprotected

In the Supabase dashboard, go to Table Editor and look for the yellow warning badge that says RLS is not enabled. You can also query: `SELECT tablename FROM pg_tables WHERE schemaname = 'public' AND tablename NOT IN (SELECT tablename FROM pg_tables WHERE rowsecurity = true);` to list unprotected tables.

3

Never use the service_role key in client-side code

The service_role key bypasses all RLS policies and should only be used in trusted server environments (API routes, edge functions, backend servers). The browser client must use the anon key, which respects RLS policies.

4

Get professional help

Still stuck? Our engineers can audit your Supabase tables, design proper RLS policies, and ensure your data is protected. Visit /services to get started.

Related technologies

Can't fix it yourself?

Our code audit identifies this issue and dozens more. Get a prioritized fix list.

Most Popular

Security Review

Security Review

from $250

Expert engineer works on your project directly. Fixed scope, fixed price, no surprises.

Request a Quote

Security Review

Full Pentest

Custom

Enterprise-grade engagement tailored to your needs. Dedicated engineer, ongoing support.

Fix Bugs

Bug Fixing

from $200

Expert engineer works on your project directly. Fixed scope, fixed price, no surprises.

Request a Quote

Fix Bugs

Ongoing Support

Custom

Enterprise-grade engagement tailored to your needs. Dedicated engineer, ongoing support.

Refactor Code

Refactoring

from $400

Expert engineer works on your project directly. Fixed scope, fixed price, no surprises.

Request a Quote

Refactor Code

Full Rewrite

Custom

Enterprise-grade engagement tailored to your needs. Dedicated engineer, ongoing support.

All projects start with a free consultation. We scope your project and provide a fixed quote before any work begins.

Frequently asked questions

What is RLS and why does it matter?

Row Level Security is a PostgreSQL feature that restricts which rows a user can access based on policies you define. Without it, anyone with your Supabase anon key (which is public by design) can read and modify every row in your tables.

How do I test that my RLS policies work correctly?

In the Supabase SQL editor, use `set role authenticated; set request.jwt.claims = '{"sub": "some-user-id"}';` then run queries to verify you only see rows belonging to that user. Also test with a different user ID to confirm you cannot access other users' data.

Does RLS slow down my queries?

The impact is minimal for well-written policies. Use `(select auth.uid())` instead of `auth.uid()` directly in policies so the value is evaluated once per query rather than once per row. Add indexes on the columns referenced in your policies (e.g., user_id) for best performance.

Still stuck? We can fix it for you.

Send us your repo. We'll diagnose the issue and give you a fixed quote within 24 hours.

Request a Quote