Supabase RLS Is Not Enough: How Vibe-Coded Apps Get Hacked
The Problem With "I Enabled RLS"
When developers enable Row-Level Security in Supabase, they often assume they're protected.
They're not — not by default.
RLS blocks direct PostgREST access, but it doesn't protect your:
service_roleUSING (true) accidentallyHow Vibe-Coded Apps Break This
When you use Cursor AI, Lovable, or Bolt to build a full-stack app, the AI generates Supabase Edge Functions that run with the service role key — which bypasses all RLS policies.
Here's a real pattern the AI generates:
// ⚠️ This bypasses ALL RLS policies
const supabase = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY! // ← this is the problem
);
export async function getUserData(userId: string) {
const { data } = await supabase
.from('users')
.select('*')
.eq('id', userId);
return data;
}
If this function is called from an API route without validating the calling user's session, any authenticated user can fetch any other user's data by simply passing a different userId.
The Three RLS Bypass Patterns
1. Service Role Key Exposure
The service_role key is meant for server-side admin tasks only. It should never be used in:
SUPABASE_SERVICE_ROLE_KEY and audit every call site.
2. Policies With USING (true)
Cursor and other AI tools sometimes generate placeholder policies that allow everything:
-- ⚠️ This policy allows anyone to read everything
CREATE POLICY "Enable read access for all users"
ON public.users
FOR SELECT
USING (true); -- ← dangerous default
Fix: Replace USING (true) with USING (auth.uid() = user_id) or an appropriate condition.
3. Missing DELETE/UPDATE Policies
Most developers add SELECT policies but forget INSERT, UPDATE, and DELETE. Supabase defaults to deny all for missing policies — but this protection breaks when you use the service role key.
The SecuriSky Detection
Our scanner specifically probes for:
userId parameter without verifying it matches request.user.idservice_role referencesA score of A or B on the free tier doesn't mean your RLS is correctly configured — we only test 3 of 18 attack surfaces on the free plan.
Quick Fix Checklist
service_role key — restrict to server-side admin onlyauth.uid() = user_id to all RLS policiesusersNext Steps
Run a full SecuriSky scan to detect RLS misconfigurations automatically, including AI-generated patterns that standard SAST tools miss.