How to Detect Missing RLS Policies Before Production
Scan for RLS drift after dashboard changes so no table reaches production unprotected.
Why RLS Drift Happens
Supabase enables RLS at the table level, but policies are often written in the Dashboard SQL Editor during development and never properly promoted. A table migrated from staging might arrive in production with RLS enabled but zero policies — meaning every authenticated request is silently denied, or worse, an anonkey can read everything if a permissive policy was left behind.
CVE-2025-48757 showed this at scale: 170+ Lovable-generated apps shipped to production without RLS policies ever being promoted from their development environments.
What SupaForge Checks
The RLS check compares both environments and reports:
- Tables with RLS enabled in source but disabled in target (or vice versa).
- Policies that exist in one environment but not the other.
- Policies with the same name but different
USINGorWITH CHECKexpressions. - Permissive vs restrictive policy type mismatches.
Step 1 — Install and Configure
npm i -g @akalforge/supaforgeCreate a configuration file pointing at your two environments. Use the connection strings from the Supabase dashboard under Settings → Database.
{
"environments": {
"staging": {
"dbUrl": "postgresql://user:pass@db.STAGING_REF.supabase.co:5432/postgres",
"projectRef": "STAGING_REF",
"apiKey": "your-staging-service-role-key"
},
"production": {
"dbUrl": "postgresql://user:pass@db.PROD_REF.supabase.co:5432/postgres",
"projectRef": "PROD_REF",
"apiKey": "your-production-service-role-key"
}
},
"source": "staging",
"target": "production"
}Step 2 — Run an RLS-Only Scan
Narrow the scan to RLS so you get a focused report without waiting for schema, data, or other checks:
supaforge scan --check rlsThe output lists every table with a discrepancy, the drift severity, and the SQL needed to fix the target environment.
Step 3 — Review Output
Each drift issue includes:
- Table name and whether RLS is enabled/disabled.
- Policy name, role, command (SELECT/INSERT/UPDATE/DELETE), and expression diff.
- Severity — critical for missing policies, warning for expression differences.
- Fix SQL — the exact
CREATE POLICYorALTER TABLE ... ENABLE ROW LEVEL SECURITYstatement.
Step 4 — Promote or Fix Manually
Preview the changes first (promote is a dry-run by default):
supaforge promoteWhen satisfied, add --apply to promote only the RLS check:
supaforge promote --check rls --applyStep 5 — Add to Your CI Pipeline
Prevent RLS drift from reaching production by adding a scan to your CI workflow. A non-zero exit code from the scan command fails the pipeline when drift is detected:
- name: Check RLS drift
run: |
npm i -g @akalforge/supaforge
supaforge scan --check rls
Summary
RLS policies are the most security-critical piece of Supabase configuration. SupaForge detects drift across environments so you never ship an unprotected table. Run scans locally, in CI, or on a schedule to stay ahead of accidental changes.