What Is This Vulnerability
Row Level Security (RLS) is PostgreSQL's built-in mechanism for controlling row-level access to tables. In Supabase, every table is exposed through the PostgREST API, meaning any client with the project's anonymous key can query tables directly. When RLS is not enabled on a table, there are zero restrictions on who can SELECT, INSERT, UPDATE, or DELETE rows. The table is completely open to the public internet.
This is the single most common and most dangerous misconfiguration in Supabase projects. Developers who are accustomed to traditional server-side frameworks often assume that the API layer handles authorization, but in Supabase the database itself must enforce access control.
Why It's Dangerous
Without RLS, an attacker who discovers your Supabase URL and anon key (both of which are embedded in client-side JavaScript) can:
- Read every row in the table, including sensitive user data, emails, addresses, and payment details
- Insert arbitrary rows, potentially polluting your data or injecting malicious content
- Update any row, modifying other users' profiles, orders, or permissions
- Delete all data in the table with a single API call
This is not a theoretical risk. Automated scanners (including AuditYourApp) routinely discover Supabase projects with dozens of unprotected tables containing production user data.
-- This table has NO RLS - fully exposed via the API
CREATE TABLE user_profiles (
id uuid REFERENCES auth.users(id),
email text,
full_name text,
phone text,
billing_address text
);
An attacker can simply run:
curl 'https://YOUR_PROJECT.supabase.co/rest/v1/user_profiles?select=*' \
-H "apikey: YOUR_ANON_KEY" \
-H "Authorization: Bearer YOUR_ANON_KEY"
How to Detect
You can query the PostgreSQL system catalog to find tables without RLS enabled:
SELECT schemaname, tablename, rowsecurity
FROM pg_tables
WHERE schemaname = 'public'
AND rowsecurity = false;
AuditYourApp automatically checks every public table in your Supabase project for RLS status and reports any tables that are unprotected. You can also check in the Supabase Dashboard under Table Editor, where a warning icon appears next to tables without RLS.
How to Fix
Enable RLS on every public table immediately, then add appropriate policies:
-- Step 1: Enable RLS (this blocks all access by default)
ALTER TABLE user_profiles ENABLE ROW LEVEL SECURITY;
-- Step 2: Add policies for legitimate access
CREATE POLICY "Users can view own profile"
ON user_profiles FOR SELECT
USING (auth.uid() = id);
CREATE POLICY "Users can update own profile"
ON user_profiles FOR UPDATE
USING (auth.uid() = id)
WITH CHECK (auth.uid() = id);
Make it a standard practice to enable RLS immediately after creating any table. You can also enforce this at the migration level by always including ALTER TABLE ... ENABLE ROW LEVEL SECURITY in the same migration that creates the table.
Scan your app for this vulnerability
AuditYourApp automatically detects security misconfigurations in Supabase and Firebase projects. Get actionable remediation in minutes.
Run Free ScanRelated
vulnerabilities
RLS Bypass: Unauthorized SELECT
Overly permissive SELECT policies allow users to read data they should not have access to, exposing sensitive information.
vulnerabilities
RLS Bypass: Unauthorized INSERT
Tables allow unauthenticated or cross-user inserts due to missing or overly permissive INSERT policies.
vulnerabilities
Public Table Read Access
Tables are readable by anonymous users through the Supabase API, potentially exposing sensitive data to unauthenticated visitors.
vulnerabilities
Public Table Write Access
Tables are writable by anonymous users, allowing unauthenticated visitors to insert, update, or delete data.