Skip to main content

ShipSafe

ShipSafe
ShipSafe
SupabaseRLSSecurityVibe Coding

Your Supabase App Has No Row Level Security: A Vibe Coder's Fix Guide

Most AI-generated Supabase apps ship with RLS disabled. That means anyone with your project URL can read, write, and delete your entire database. Here's how to lock it down in 15 minutes.

6 min read

If you built a Supabase app with an AI coding tool — Lovable, Bolt, v0, Cursor, or Replit — there is a high chance your database is wide open. Not theoretically. Literally anyone with your project URL can read your entire users table, modify records, or delete everything.

The reason is Row Level Security (RLS). Supabase is built on Postgres, and RLS is the mechanism that controls who can access which rows. When it is disabled — which is the default state and what most AI tools leave it at — the Supabase anon key (which is public and embedded in your frontend code) grants full access to every row in the table.

This is the single most common critical vulnerability we find in vibe-coded apps. Here is how to check if you are exposed and how to fix it in about 15 minutes.

Want to check your own app?

Paste your GitHub URL and get a security report in under 2 minutes. Free scan, no credit card required.

Scan My App Free

Why This Is a Critical Issue

Your Supabase anon key is not a secret. It is designed to be public — it ships in your frontend JavaScript bundle where anyone can see it in browser DevTools. Supabase's security model assumes you will use RLS to limit what the anon key can do. Without RLS policies, that key is a master key to your database.

An attacker does not need to hack anything. They open your app, grab the URL and anon key from the network tab, and use the Supabase JavaScript client to query any table directly. In under a minute they can dump your users table, read private messages, or delete records.

Step 1: Check Which Tables Are Exposed

Run this SQL query in your Supabase SQL Editor to see every public table and its RLS status:

SELECT
  schemaname,
  tablename,
  rowsecurity
FROM pg_tables
WHERE schemaname = 'public';

Any table where rowsecurity is false is fully exposed to anyone with your anon key.

Step 2: Enable RLS on Every Table

For each exposed table, enable RLS. This immediately blocks all access until you add explicit policies:

-- Enable RLS (blocks all access by default)
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.posts ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.messages ENABLE ROW LEVEL SECURITY;

Step 3: Add Access Policies

Now add policies that define exactly who can do what. The most common pattern is: users can read and write their own data.

-- Users can read their own profile
CREATE POLICY "Users read own profile"
  ON public.profiles FOR SELECT
  USING (auth.uid() = user_id);

-- Users can update their own profile
CREATE POLICY "Users update own profile"
  ON public.profiles FOR UPDATE
  USING (auth.uid() = user_id);

-- Users can insert their own profile
CREATE POLICY "Users insert own profile"
  ON public.profiles FOR INSERT
  WITH CHECK (auth.uid() = user_id);

For public content like blog posts that anyone can read but only authors can edit, combine a permissive SELECT policy with a restricted UPDATE policy.

Bonus: Never Use the Service Role Key in the Frontend

Some AI tools work around RLS by using the Supabase service role key instead of the anon key. This key bypasses all RLS policies and has full admin access. If it appears anywhere in your frontend code, your entire database is exposed regardless of your policies.

The service role key should only be used in server-side code: API routes, Server Actions, or backend services. Never in client-side JavaScript, React components, or environment variables prefixed with NEXT_PUBLIC_.

Fix It Once, Ship Forever

Enabling RLS and writing policies takes about 15 minutes. It is the single highest-impact security fix you can make on a Supabase app. Once your policies are in place, you can ship updates confidently knowing your data is protected at the database level.

ShipSafe detects missing RLS, exposed service keys, and dozens of other Supabase-specific vulnerabilities automatically. Run a free scan at ship-safe.co.

Want to check your own app?

Paste your GitHub URL and get a security report in under 2 minutes. Free scan, no credit card required.

Scan My App Free