afterbuild/ops
§ EX-07/supabase-expert
Supabase expert for AI-built apps

Supabase expert for AI-built apps — Supabase RLS fix, Supabase auth fix, Supabase server-side client done right

By Hyder Shah12 min readLast updated 2026-04-15
Quick verdict

A Supabase expert for AI-built apps fixes the things the AI builder left broken. Roughly 70% of Lovable apps ship with Supabase RLS disabled, and a February 2026 incident exposed 18,000 users across 170 AI-built apps (The Register). We run a Supabase RLS fix, apply the Supabase auth fix for callbacks and sessions, wire the Supabase server-side client correctly, tune connection pools, and kill N+1 queries — fixed price, starting with a 48-hour security audit at $499.

Why AI builders ship broken Supabase

Supabase is the backend of choice for Lovable, Bolt.new, Base44, and most v0 projects with a database. The tools are excellent at generating tables and CRUD. They are terrible at the parts that keep data private and fast: row-level security policies, connection pooling, indexes, auth redirect URLs, and idempotent writes.

The default Supabase posture is permissive. A new table has RLS disabled until you turn it on, and AI builders rarely prompt you to. Veracode's 2025 AI code study found 48% of generated code contains known vulnerabilities; Supabase misconfiguration is the single most common class in the apps we audit. The Register documented 170 Lovable apps leaking 18,000 users' data — authenticated users were blocked, unauthenticated visitors had full read access.

The second failure mode is scale. AI-generated clients often call the Supabase REST API from the browser with the anon key and fetch entire tables, then filter client-side. A prototype with 200 rows runs fine. The same app at 20,000 rows times 50 concurrent users exhausts the default connection pool, times out, and crashes. A Supabase expert rewrites these hot paths, adds indexes, moves sensitive reads to Edge Functions, and introduces PgBouncer / Supavisor pooling.

Source: The Register, Feb 2026 — 170 Lovable apps leaked 18,000 users' data through disabled RLS

§ MATRIX/ai-builder / failure-mode

Which AI builder shipped your broken Supabase?

The Supabase failure mode usually depends on the tool that shipped the code. Find your builder below, then read the matching problem page.

AI builderWhat breaks in SupabaseGo to
LovableRLS disabled by default on generated tables. Auth callback still points at preview URL. Direct anon-key reads from browser leak full tables.Lovable RLS fix
Bolt.newSchema drift between Supabase dashboard and code. No migrations folder. Service role key accidentally committed to repo.Bolt.new rescue
v0Frontend-only output calls Supabase directly from the client with no RLS planning. Auth state not hydrated on SSR.v0 backend fix
CursorRegression loop on RLS policies — fixes one table, breaks policies on two others. Forgets schema context by file seven.Cursor regression fix
Replit AgentUses Replit's own DB for prototypes, swaps to Supabase late. Migration is rushed; RLS is an afterthought.Replit database fix
Claude CodeWrites clean RLS when told to; silently skips it when not. Multi-file refactors miss policy updates.Claude Code refactor fix
WindsurfEnterprise patterns don't auto-apply to Supabase-specific constructs. RLS treated as optional.Windsurf rescue
Base44Closed platform wraps Supabase; you can't see the generated policies. Export lands in a repo with RLS off.Base44 backend fix
§ ANATOMY/supabase / failure

Anatomy of a Supabase RLS failure in an AI-built app

The Register's Feb 2026 disclosure cited the exact pattern: 170 Lovable-built apps leaking data from 18,000 users, every one of them running on Supabase, every one with RLS either disabled or inverted. The failure mode has a name now — 'authenticated users were blocked; unauthenticated visitors had full access.' We've rescued four apps from that list since the disclosure. The mechanics repeat.

A founder prompts Lovable: 'let users sign up and save their own tasks.' Lovable creates a `tasks` table, hooks up sign-up via Supabase Auth, and wires the frontend to call `supabase.from('tasks').select('*')`. It works in preview — there are two users and three tasks, and the frontend filters by user_id client-side because the database returns everything. RLS was never enabled. The Supabase anon key, which is embedded in the JavaScript bundle by design, grants full read to every row. When the app launches publicly, anyone can fetch every user's tasks by opening DevTools and copying the query.

The fix is disciplined: `ALTER TABLE tasks ENABLE ROW LEVEL SECURITY;` plus a policy `CREATE POLICY user_owns_tasks ON tasks FOR ALL USING (auth.uid() = user_id);`.
Hyder Shah· Supabase rescue engineer

The fix is disciplined: `ALTER TABLE tasks ENABLE ROW LEVEL SECURITY;` plus a policy `CREATE POLICY user_owns_tasks ON tasks FOR ALL USING (auth.uid() = user_id);`. We then verify with a test: log in as user A, attempt to read user B's task ID, confirm 0 rows returned. We also test the inversion — with the policy wrong, the test catches it. Finally, we add a CI check that queries `pg_tables` and fails the build if any table without RLS is in the app schema. That single check would have caught every one of the 170 breached apps before their first real user.

The broader lesson is that Supabase's posture is neither secure nor insecure by default — it's 'ask for what you want.' Permissive is the baseline. Every team that launches without an explicit RLS policy per table is one curl command away from the next disclosure headline.

§ RESCUE/supabase / engagement

What a Supabase rescue engagement ships

From first diagnostic to production handoff — the explicit steps on every Supabase engagement.

  1. 01

    Free 30-minute diagnostic

    Send us your Supabase project URL (read-only), the AI builder you used, and the symptom. Inside 24 hours we return a written rescue-vs-rewrite recommendation with a fixed price.

  2. 02

    48-hour security audit

    We enumerate every table, verify RLS is enabled, check policies per role, scan for anon-key exposure, look for service-role keys in the client bundle, and confirm auth redirect URLs match production. Delivered as a written report with code patches.

  3. 03

    Integration and query fix

    We fix the specific breaks: auth callbacks, OAuth redirects, webhook handlers, N+1 queries, missing indexes. One fixed-price engagement per integration — Stripe, email, domain — delivered in 3 to 5 days.

  4. 04

    Production deploy pass

    We introduce migrations (Supabase CLI or Drizzle), move the DB to a pooled connection string via Supavisor, wire environment variables to Vercel / Fly / Railway, and set up error tracking with Sentry.

  5. 05

    Handoff and retainer

    You get a written delivery doc, a Loom walkthrough, and the option of a $3,499/mo retainer for 40h of engineering plus priority rescue queue. Most clients stay on retainer for the first 3 months after launch.

§ AUDIT/supabase / first-pass

Every Supabase rescue audit checks

The diagnostic pass on every Supabase rescue. Each item takes under 10 minutes; together they cover the patterns that cause 90% of AI-built-app failures.

  1. 01
    RLS enabled on every app-schema table

    We query `pg_class` for `relrowsecurity = true` on every table in the public schema. Missing entries are critical findings.

  2. 02
    Non-trivial policies per role

    `USING (true)` satisfies 'RLS enabled' but enforces nothing. We verify each policy filters by auth.uid() or role.

  3. 03
    Service-role key surface

    Service-role key must not appear in any NEXT_PUBLIC_ variable or client bundle. We grep the built JS and repo for service_role patterns.

  4. 04
    Anon-key read coverage

    We script a query as the anonymous role against every table and confirm zero user-private rows returned.

  5. 05
    Auth redirect URL allowlist

    Supabase auth redirect allowlist must include production URLs exactly. Missing or typo'd entries cause password reset links to break in production.

  6. 06
    Connection pooler mode

    Serverless routes should connect via Supavisor transaction mode, not the direct 5432 connection. We verify the connection string.

  7. 07
    pg_stat_statements enabled and sampled

    Without this extension we can't identify slow or hot queries. We enable it and capture a baseline.

  8. 08
    Indexes on foreign keys and RLS-filtered columns

    RLS policies that filter by user_id need user_id indexed — otherwise the policy forces a seq scan on every SELECT.

  9. 09
    Migrations folder in git

    If the Supabase dashboard state can't be reproduced from the repo, rollback is impossible. We introduce Supabase CLI migrations.

  10. 10
    Auth email templates configured for production

    Default Supabase auth emails point at the project's auto-domain. We swap to branded sender + production URLs.

  11. 11
    Storage bucket policies

    Storage RLS is separate. Buckets default to public. We verify every bucket's read/write policies.

  12. 12
    Realtime channel filter scope

    Realtime broadcasts to any subscribed client. We check that filters restrict per-user data and that RLS applies to realtime as well.

§ DIFF/supabase / before-after

Common Supabase patterns we fix

These are the shapes AI-generated code arrives in — and the shape we leave behind.

The RLS-disabled table with user data
✕ before · ai-shipped
tsx
01`tasks` table with no RLS. Anon key lets anyone read every task in the DB. 170-Lovable-apps pattern.
The RLS-disabled table with user data
✓ after · afterbuild
tsx
01RLS enabled. `CREATE POLICY user_owns_tasks ON tasks FOR ALL USING (auth.uid() = user_id)`. Tested against anonymous, authenticated-as-wrong-user, and authenticated-as-owner.
The RLS-disabled table with user data
The service role key in the browser
✕ before · ai-shipped
tsx
01`NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY` in .env.local. Ships to every client. Full DB access from any user's DevTools.
The service role key in the browser
✓ after · afterbuild
tsx
01Service role key named without NEXT_PUBLIC_, used only in server components and API routes. CI check forbids accidental re-exposure.
The service role key in the browser
The client-side filter on an unbounded select
✕ before · ai-shipped
tsx
01`supabase.from('transactions').select('*')` returns 40,000 rows to the browser, which filters client-side.
The client-side filter on an unbounded select
✓ after · afterbuild
tsx
01WHERE pushed to SQL, LIMIT applied, user_id filter enforced by RLS anyway. Response drops from 30 MB to 10 KB.
The client-side filter on an unbounded select
The connection-per-request client
✕ before · ai-shipped
tsx
01`createClient()` inside every API route handler. Each request holds a pool slot. Default Supabase pool exhausts at 50 concurrent requests.
The connection-per-request client
✓ after · afterbuild
tsx
01Pooled singleton via Supavisor transaction mode. Same traffic, no exhaustion. Verified under k6 load.
The connection-per-request client
The missing index behind RLS
✕ before · ai-shipped
tsx
01Policy `USING (auth.uid() = user_id)` on a 200k-row table with no index on user_id. Every SELECT seq-scans. 12-second queries.
The missing index behind RLS
✓ after · afterbuild
tsx
01`CREATE INDEX ON transactions (user_id)`. Index scan with RLS applied. 50ms queries.
The missing index behind RLS
The auth callback stuck on preview URL
✕ before · ai-shipped
tsx
01Supabase auth callback configured as `https://preview.lovable.app/auth/callback`. Production password resets redirect to preview. Users can't log in.
The auth callback stuck on preview URL
✓ after · afterbuild
tsx
01Allowlist updated with production domain, preview domain, and localhost for dev. Tested on each.
The auth callback stuck on preview URL
The storage bucket without policies
✕ before · ai-shipped
tsx
01Bucket `user-uploads` defaults to private-but-no-policy. Dashboard says 'private', but any authenticated user can read any other user's files.
The storage bucket without policies
✓ after · afterbuild
tsx
01Explicit bucket policy: `auth.uid()::text = (storage.foldername(name))[1]`. Users can only access their own folder.
The storage bucket without policies
§ FLAGS/supabase / red-signals

Supabase red flags in AI-built code

If any of these are true in your repo, the rescue is probably worth more than the rewrite.

flag
signal
why it matters
`SELECT relname FROM pg_class WHERE relrowsecurity = false AND relnamespace = 'public'::regnamespace` returns any row
An app-schema table has RLS disabled. Direct exposure via the anon key.
Any RLS policy uses `USING (true)`
Enforces nothing. Satisfies the 'enabled' check while leaving the table fully readable.
NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY appears in env or the client bundle
Service role key ships to every browser. Full DB admin from any user's DevTools.
The Supabase URL in production matches the preview project URL
You're pointed at the preview database. Production users and preview users share the same tables.
Stripe webhook handler returns 200 without calling `stripe.webhooks.constructEvent`
Forgeable. Any attacker can flip orders to paid, trigger refunds, spoof subscription events.
No migrations folder or a `supabase/migrations` folder out of sync with the live schema
The database state can't be reproduced, rolled back, or audited.
'connection pool exhausted' in Supabase logs even at moderate load
The code is not using Supavisor's transaction pooler, or is opening a fresh client per request.
§ PRICING/supabase / fixed-price

Fixed-price Supabase engagements

No hourly meter. Scope agreed up front, written fix plan, delivered on date.

price
$0
turnaround
Free rescue diagnostic
scope
30-min call plus written rescue-vs-rewrite recommendation in 24 hours.
View scope
featured
price
$499
turnaround
Security audit
scope
RLS, auth, secrets, OWASP review of your Supabase project. 48-hour turnaround.
View scope
price
$799
turnaround
Integration fix
scope
One Supabase integration — Stripe, auth, domain, email — done right, fixed price.
View scope
price
$1,999
turnaround
Deploy to production
scope
Env vars, CI/CD, SSL, monitoring, rollback. 7-day delivery.
View scope
§ EXAMPLES/supabase / real-scopes

What Supabase rescues actually cost

Anonymized, representative scopes from recent Supabase rescues. Every price is the one we actually quoted.

Small rescue
$499

A solo founder on Lovable with 6 tables, RLS off everywhere, 120 beta users. We enable RLS, write policies, verify with a test suite.

Scope
RLS audit and remediation across 6 tables, policy tests, written report.
Duration
48 hours
Medium rescue
$3,499

A seed-stage SaaS on Bolt + Supabase. 23 tables, auth half-wired, Stripe webhooks unsigned, connection pooling misconfigured.

Scope
Full security audit, RLS rewrite, auth callback fix, Supavisor pooling, Stripe signature verification, migrations introduced.
Duration
2 weeks
Large rescue
$9,999+

A growth-stage fintech with 40k monthly users on Supabase, complex RBAC, regulatory inquiry requiring RLS audit trail.

Scope
Full RLS rewrite with RBAC, audit log triggers, performance tuning including indexes and pooler mode, 6-week engagement.
Duration
6 weeks
§ RUNBOOK/supabase / references

Supabase runbook and reference material

The documentation, CLIs, and specs we rely on for every Supabaseengagement. We cite, we don't improvise.

§ FAQ/supabase / founders-ask

Supabase questions founders ask

FAQ
Why does my Lovable app need a Supabase RLS fix?
Lovable generates Supabase tables with RLS in its default off state. Unless you explicitly prompted for policies, the tables are readable and writable by anyone with your anon key — which ships in every client bundle. The Supabase RLS fix a Supabase expert for AI-built apps runs is to enable row-level security on every app-schema table and write scoped policies. Research suggests roughly 70% of Lovable apps need this fix.
Is the Supabase anon key in the browser safe without a Supabase RLS fix?
No. The anon key is public by design, but it grants full table access until a Supabase RLS fix is applied. With RLS enabled and correctly scoped policies per table, the anon key is safe and intended to be in the browser. Without the fix, the 170-broken-Lovable-apps incident (The Register, Feb 2026) is the blueprint for what happens next.
How much does a Supabase expert for AI-built apps cost?
Our security audit — which includes a Supabase RLS fix scope and a Supabase auth fix scope — is $499 with a 48-hour turnaround, delivered as a written report with code patches. Integration fixes (Supabase auth fix, Stripe webhooks, email) are $799 each. A full deploy-to-production pass wiring the Supabase server-side client, env vars, monitoring, and pooled connections is $1,999. Larger rescues start at $3,999. No hourly billing.
Why is my Supabase app slow under real traffic — Supabase query performance?
Supabase query performance drops for three reasons: connection pool exhaustion (Supabase's default pool is 15 connections — every fresh client steals one), missing indexes on filter columns, and unbounded queries that load entire tables to filter in the browser. A Supabase expert for AI-built apps routes traffic through Supavisor's transaction pooler, adds the indexes your query planner needs, and pushes filters into SQL.
Can I keep using Lovable while a Supabase expert runs the fixes?
Yes, for a while. A Supabase expert for AI-built apps locks down RLS policies and adds Edge Functions for dangerous paths. Lovable's chat-driven edits won't overwrite these if they only touch frontend files. For a permanent fix, most clients export the repo and have us take over production work in Next.js — with the Supabase server-side client wired correctly — while they keep prototyping in Lovable.
Do I need Supabase migrations? My AI builder didn't set them up.
Yes. Without migrations, you can't reproduce your Supabase database in staging or recover from a schema mistake. A Supabase expert for AI-built apps introduces Supabase CLI migrations (or Drizzle on a portable Next.js stack), backfills them from your current schema, and wires them to CI. It's one of the first fixes on every rescue and a prerequisite for a clean Supabase auth fix.
What is the right Supabase auth fix for an AI-built app — stay on Supabase Auth or switch to Clerk?
Supabase Auth ships with every AI builder that uses Supabase, but password reset and email verification flows are usually half-wired. The Supabase auth fix we run fixes callback URLs, session refresh, the server-side client, and email templates. Clerk is a drop-in alternative with stronger session management. We fix Supabase Auth in place when you're staying on Supabase, and migrate to Clerk when we're escaping to Next.js.
How does a Supabase expert audit without breaking my live app?
Read-only. A Supabase expert for AI-built apps requests a read-only service role key or a temporary collaborator invite with viewer access. The audit — including the Supabase RLS fix scope and Supabase query performance review — runs offline against a schema snapshot. We deliver the fix as a pull request plus SQL migration files. You or your team apply them after reviewing.
Next step

Your AI builder shipped broken Supabase. We ship the fix.

Send the repo. We'll tell you exactly what's wrong in your Supabase layer — and the fixed price to ship it — in 48 hours.

Book free diagnostic →