Impact
Failure to implement Row Level Security (RLS) allows unauthenticated attackers to query data from a Supabase database when public tables are exposed through the anon boundary [S1]. Because Next.js applications typically expose the Supabase anon key in client-side code, an attacker can use this key to make direct REST API calls to the database, bypassing the intended application logic and accessing sensitive user information [S2].
Root Cause
By default, Postgres tables in Supabase require explicit activation of Row Level Security to prevent public access [S1]. When a developer creates a table but forgets to enable RLS or fails to define restrictive policies, the database may expose data to anyone possessing the project's anon key [S1]. In Next.js applications, server-side rendering and client-side fetching also require careful Supabase client setup so authenticated user context reaches the database layer [S2].
Concrete Fixes
- Enable RLS: Execute
ALTER TABLE "your_table_name" ENABLE ROW LEVEL SECURITY;for every public table that stores app data [S1]. - Define Policies: Create specific policies that restrict access based on the user's authentication status, such as
CREATE POLICY "Users can see their own data" ON your_table_name FOR SELECT USING (auth.uid() = user_id);[S1]. - Secure Server-Side Clients: When using Next.js, keep service-role clients server-only and still apply ownership filters before returning data to users [S2].
How FixVibe tests for it
FixVibe already runs a read-only Supabase RLS check through baas.supabase-rls. The scanner discovers the Supabase project URL and public anon key from same-origin JavaScript bundles, asks PostgREST for public table metadata, and attempts limited read-only selects to confirm whether data is exposed without a user session. It does not insert, update, delete, or use service-role credentials. Repo scans can also catch this earlier through repo.supabase.missing-rls, which flags SQL migrations that create public tables without ENABLE ROW LEVEL SECURITY.
