# Diagnosing & Locking Down Lovable + Supabase RLS Leaks, Broken Magic Links & Exposed Keys

Canonical URL: https://aquarel.io/teardowns/lovable-supabase-rls-auth-rescue
Author: Dositej Grbović (Founder & Principal Engineer)
Type: stack-teardown | Published: 2026-02-01 | Updated: 2026-02-18
Stack: Lovable.dev, Supabase, PostgreSQL RLS, Supabase Auth, Deno Edge Functions

> Lovable + Supabase applications frequently reach 80% completion with wide-open PostgreSQL tables because AI prompts disable Row-Level Security (RLS) or add permissive USING (true) policies to bypass query errors. Locking down production requires enforcing tenant-scoped auth.uid() policies, moving privileged mutations to Deno Edge Functions, and rotating leaked service-role keys.

## Symptom-to-Fix Diagnostic Matrix

| Symptom | Root Technical Cause | Surgical Engineering Fix |
| --- | --- | --- |
| Any logged-in or anonymous user can query all rows in public.profiles or public.subscriptions via browser DevTools | AI migration script ran ALTER TABLE ... DISABLE ROW LEVEL SECURITY or created a policy with USING (true) to fix an empty UI table. | Enable RLS on every public table and enforce strict `(SELECT auth.uid()) = user_id` SELECT/INSERT/UPDATE/DELETE policies. |
| Magic links or Google OAuth sign-ins redirect back to `/login` or crash on first signup | Missing `SECURITY DEFINER` trigger on `auth.users` to provision `public.profiles` atomically before client queries run. | Install an atomic PostgreSQL trigger on `auth.users` and handle PKCE code exchange cleanly on the callback route. |
| Frontend calls Stripe or admin Supabase queries using `VITE_SUPABASE_SERVICE_ROLE_KEY` | AI assistant placed the admin service_role secret into `VITE_*` client environment variables to bypass RLS restrictions. | Immediately rotate the service_role key in Supabase Dashboard and move privileged logic into verified Supabase Edge Functions. |

## Copy-Pasteable Production Guardrail: `CLAUDE.md`

Copy-pasteable Supabase RLS & Secret Isolation rules for Lovable / Claude Code repositories.

```markdown
# Aquarel Vibe-Safe Handover: Supabase & Lovable Security Guardrails
## 1. Row-Level Security (RLS) Rules (NON-NEGOTIABLE)
- NEVER run `DISABLE ROW LEVEL SECURITY` or `USING (true)` on tenant data tables (`profiles`, `subscriptions`, `documents`).
- Every migration in `supabase/migrations/*.sql` MUST enable RLS and scope policies to `(select auth.uid()) = user_id`.

## 2. Environment Variable Isolation
- NEVER prefix `SUPABASE_SERVICE_ROLE_KEY` or `STRIPE_SECRET_KEY` with `VITE_` or `NEXT_PUBLIC_`.
- All privileged mutations and webhook handlers MUST execute inside `supabase/functions/*` Deno Edge Functions.
```

## Diagnostic Walkthrough

## Why AI Assistants Disable Supabase Row-Level Security

When you tell an AI coding assistant *"My dashboard isn't showing any data,"* the assistant often diagnoses a Supabase permission error and fixes it by generating a migration with `USING (true)` or disabling RLS altogether. While that makes data appear on your screen immediately, it also allows anyone with your public `anon` key to read or modify every customer's records.

### Broken AI Pattern vs. Surgical Engineering Fix

- **Broken AI Pattern**: Prompting Lovable or Claude Code to "fix empty dashboard query" causes it to run `ALTER TABLE public.subscriptions DISABLE ROW LEVEL SECURITY;` or `CREATE POLICY "Allow all" ON public.profiles FOR ALL USING (true);`, while embedding `VITE_SUPABASE_SERVICE_ROLE_KEY` in browser code.
- **Surgical Engineering Fix**: Re-enable RLS on every table, enforce `USING ((select auth.uid()) = user_id)` and `WITH CHECK ((select auth.uid()) = user_id)`, provision user rows via a `SECURITY DEFINER` trigger on `auth.users`, and isolate privileged Stripe/admin mutations inside verified Deno Edge Functions.

In our 3–7 day **Lovable + Supabase Rescue Sprint**, we audit every table, write tenant-isolated RLS policies backed by `(select auth.uid()) = user_id`, move secret-key logic into Deno Edge Functions, and lock those rules into your repo's `CLAUDE.md`.

## Related Services & Proof Assets

- [Service: lovable-supabase-rescue](https://aquarel.io/services/lovable-supabase-rescue)
- [Service: vibe-code-app-rescue](https://aquarel.io/services/vibe-code-app-rescue)
- [Case Study: inherited-web-app-stabilization-without-rewrite](https://aquarel.io/case-studies/inherited-web-app-stabilization-without-rewrite)

## Frequently Asked Questions

### How can I tell if my Lovable + Supabase app has exposed tables right now?

Open your Supabase Dashboard and check the Security Advisor tab, or inspect your network requests in Chrome DevTools. If any table shows 'RLS Disabled' or uses a policy with `USING (true)` for sensitive customer rows, your database is exposed.

### Will enabling Supabase RLS break my existing Lovable frontend queries?

Only if your frontend was querying rows without an authenticated session or missing `user_id` filters. During a Rescue Sprint, we align both the PostgreSQL RLS policies and the frontend Supabase client hooks so every legitimate user query succeeds.

### Can Aquarel audit my Supabase RLS posture before we commit to a sprint?

Yes. Every qualified founder receives a complimentary 48-hour Initial Codebase Audit ($0) after our 20-minute Triage Call and mutual NDA.

## Need Surgical Help With This Stack?

- [Book Free 20-Min Triage Call or Send Broken App Async](https://aquarel.io/triage?stack=lovable,supabase)
