Database security
Supabase security for vibe-coded apps
Protect a Supabase app with Row Level Security, correct key placement, tenant-aware policies, storage rules, and server-only administrative access.
Supabase makes a browser-to-database product possible with very little code. The safety of that design depends on Row Level Security and the difference between a publishable key and a privileged server key.
A working login screen proves authentication. It does not prove that one user cannot read or update another user's rows.
Enable RLS on every exposed table
Supabase says Row Level Security must be enabled on tables in an exposed schema such as public. Tables created in the dashboard receive RLS by default, but raw SQL migrations need an explicit ALTER TABLE statement. Check migrations, not only the current dashboard state.
- Enable RLS before production data is written.
- Create separate policies for select, insert, update, and delete when their rules differ.
- Test as anon, as a signed-in user, as another tenant, and with no session.
- Apply the same ownership model to storage objects and database functions.
A policy must match the tenant model
A check such as user_id = auth.uid() works for rows owned directly by one user. Team SaaS products usually need membership joins, organization IDs, role checks, and rules for invitations or suspended accounts. Copying a single-user policy into a multi-tenant app can either expose data or block legitimate work.
Write tests that create two tenants and attempt every read and write across the boundary. The denied case is the test that matters.
Keep privileged keys on the server
Supabase publishable keys and legacy anon keys are intended for public clients when RLS is correct. Secret keys and legacy service-role keys bypass RLS and belong only in controlled backend code. Never give them a NEXT_PUBLIC_, VITE_, or REACT_APP_ prefix.
Review server routes too
A server route using a privileged Supabase client becomes its own authorization boundary. Verify the signed-in user, check the tenant and role, validate the input, then perform the administrative query. The service key will not repair a missing authorization check.
Primary source
Check your repository
See which of these issues are visible now.
ScanMySaaS reads a bounded set of security-relevant files from a public GitHub repository. It never runs repository code or reveals matched secret values.
Scan a public repository