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 dashboardSupabase dashboard: 'RLS is not enabled on this table'Any authenticated user can access all rows in the tableAnonymous users can query the table without restrictionsWhy this happens in AI-generated code
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.
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.
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
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.
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.
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.
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.
Security Review
Security Review
Expert engineer works on your project directly. Fixed scope, fixed price, no surprises.
Request a QuoteSecurity Review
Full Pentest
Enterprise-grade engagement tailored to your needs. Dedicated engineer, ongoing support.
Fix Bugs
Bug Fixing
Expert engineer works on your project directly. Fixed scope, fixed price, no surprises.
Request a QuoteFix Bugs
Ongoing Support
Enterprise-grade engagement tailored to your needs. Dedicated engineer, ongoing support.
Refactor Code
Refactoring
Expert engineer works on your project directly. Fixed scope, fixed price, no surprises.
Request a QuoteRefactor Code
Full Rewrite
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.
Related resources
Related Technologies
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.