fixes / launch-ready

How I Would Fix database rules leaking customer data in a Lovable plus Supabase client portal Using Launch Ready.

The symptom is usually ugly and obvious: one customer logs in and sees another customer's records, files, invoices, or messages. In a client portal, that...

How I Would Fix database rules leaking customer data in a Lovable plus Supabase client portal Using Launch Ready

The symptom is usually ugly and obvious: one customer logs in and sees another customer's records, files, invoices, or messages. In a client portal, that is not just a bug. It is a trust break, a support fire, and potentially a data incident.

The most likely root cause is weak or missing Supabase Row Level Security (RLS), or policies that look correct but do not actually bind every query to the authenticated user. The first thing I would inspect is the exact table policy setup in Supabase, then I would trace the frontend queries coming from Lovable to see whether the app is querying a shared table without a user filter or using an admin key where it should never do that.

Triage in the First Hour

1. Freeze new releases.

  • Stop any auto-deploys from Lovable or connected CI.
  • If data exposure is active, I would treat this as a production incident until proven otherwise.

2. Confirm scope in Supabase logs.

  • Check API logs for suspicious broad reads on customer tables.
  • Look for repeated `select` calls returning more rows than expected.

3. Inspect RLS status on every customer-facing table.

  • Verify RLS is enabled on all tables holding customer data.
  • Confirm policies exist for `select`, `insert`, `update`, and `delete` where needed.

4. Review service role usage.

  • Search the codebase for `service_role`, admin keys, or backend functions that bypass RLS.
  • Make sure no client-side bundle contains privileged secrets.

5. Check Lovable-generated queries.

  • Open the portal screens that show customer records.
  • Trace which Supabase tables they hit and whether filters are applied by `user_id`, `account_id`, or tenant ID.

6. Validate auth context.

  • Confirm users are signed in before any protected data loads.
  • Check whether the app reads from stale sessions or missing JWT claims.

7. Inspect storage buckets too.

  • Customer files often leak through public buckets even when tables are protected.
  • Verify bucket policies and signed URL behavior.

8. Review recent schema changes and deployments.

  • Look for newly added columns, renamed foreign keys, or copied tables with no policies.
  • Check if a migration reset policies after a deploy.

9. Test with two separate accounts.

  • Use one test customer A and one test customer B.
  • Confirm A cannot list, fetch, or guess B's records from UI or direct API calls.

10. Capture evidence before changing anything.

  • Save screenshots, policy exports, logs, and timestamps.
  • This helps if you need to explain impact to clients later.
-- Quick check: list tables with RLS status in Supabase/Postgres
select schemaname, tablename, rowsecurity
from pg_tables
join pg_class on pg_class.relname = tablename
join pg_namespace on pg_namespace.nspname = schemaname
where schemaname = 'public'
order by tablename;

Root Causes

1. RLS is disabled on one or more sensitive tables.

  • How to confirm: inspect table settings in Supabase and run the query above.
  • If `rowsecurity` is false on any customer table, that is your first fix target.

2. Policies exist but are too broad.

  • How to confirm: read each policy carefully for conditions like `true`, missing tenant checks, or use of weak joins.
  • A policy that says "authenticated users can select" without matching ownership is effectively open access.

3. The frontend uses an admin key or server credential incorrectly.

  • How to confirm: search Lovable-generated code and environment variables for privileged keys exposed to browser code.
  • If the browser can read it, assume an attacker can too.

4. Queries do not filter by tenant or owner correctly.

  • How to confirm: inspect each portal screen query and verify it includes a strict match such as `account_id = auth.uid()`-backed mapping or tenant membership logic.
  • Missing filters often happen when screens are cloned quickly inside Lovable.

5. Foreign key relationships expose related rows indirectly.

  • How to confirm: test joins across profiles, invoices, messages, and attachments.
  • A secure parent table does not help if child tables are still public.

6. Storage buckets or signed URLs are misconfigured.

  • How to confirm: check bucket privacy settings and whether URLs can be guessed or reused too long.
  • File leaks often happen after people fix database rules but forget file access rules.

The Fix Plan

1. Lock down access first, then repair behavior second.

  • I would enable RLS on every table containing customer data before touching UI polish or new features.
  • If there is active leakage, I would prefer temporary breakage over continued exposure.

2. Replace broad policies with ownership-based policies.

  • Use explicit tenant membership checks or direct user ownership checks on every sensitive table.
  • Do not rely on front-end filtering alone. The database must enforce access even if the UI fails.

3. Separate public data from private data models.

  • Keep marketing content and public metadata in separate tables from portal records.
  • This reduces accidental joins and makes reviews easier.

4. Audit every screen generated by Lovable that reads customer data.

  • I would verify each query against its intended user story:

1. Who should see this? 2. What row proves they own it? 3. What happens if the filter fails?

5. Remove privileged secrets from client code immediately.

  • Move service role operations into server-only functions or edge functions with strict checks before execution.
  • Rotate any exposed secret after removal.

6. Tighten storage access at the same time as table access.

  • Make private buckets private by default.
  • Serve files through signed URLs with short expiration windows like 5 to 15 minutes.

7. Add defensive defaults in the app layer.

  • Hide portal pages until auth state resolves cleanly.
  • Show loading states instead of rendering potentially stale shared data during session transitions.

8. Rotate keys and review audit trails after containment.

  • Rotate Supabase keys if there was any chance of exposure beyond RLS failure alone.
  • Review access logs for unusual volume before reopening normal traffic.

9. Ship in one controlled deploy window only after validation passes.

  • I would not mix security fixes with redesign work in the same release unless necessary for containment reasons.

Regression Tests Before Redeploy

I would not redeploy until these pass:

1. Two-user isolation test

  • Customer A cannot read Customer B's rows through UI or direct API requests.
  • Acceptance criteria: zero cross-account records returned in 20 repeated attempts.

2. Auth bypass test

  • Unauthenticated users cannot access protected endpoints or private pages.
  • Acceptance criteria: redirect to login or return 401/403 consistently.

3. Role test

  • Admin-only workflows remain available only to approved staff accounts.

| Test | Expected result | | --- | --- | | Standard user reads own record | Allowed | | Standard user reads other record | Denied | | Anonymous request | Denied | | Admin action without staff claim | Denied |

4. Storage test

  • Private documents cannot be fetched by guessing URLs alone if signed access expires properly.

5. Query coverage check ```bash npm test && npm run lint && npm run build ``` Add at least one integration test per sensitive table path if you have CI set up already.

6. Manual exploratory test -- Log in as two different customers on separate browsers or incognito windows -- Open dashboard, invoices, messages, attachments, profile pages -- Confirm no cross-tenant content appears during refreshes or back navigation

7. Error-state check Acceptance criteria: 1. Failed fetches do not reveal raw database errors to users 2. Empty states do not show another user's data as fallback 3. Loading states do not cache old account content

8. Security review gate Acceptance criteria: 1. No secret keys in client bundles 2. All sensitive tables have RLS enabled 3. All policies are reviewed line by line before deploy

Prevention

1. Make RLS part of code review, not an afterthought.

  • Every schema change should include policy changes in the same pull request where possible。
  • I would reject changes that add sensitive tables without policies attached.

2. Add a simple security checklist for AI-built edits from Lovable or similar tools。

  • Does this screen touch customer data?
  • Which row-level rule protects it?
  • Is any admin credential exposed to the browser?
  • Does this change alter file access too?

3. Monitor for anomalous reads and policy failures。

  • Set alerts for spikes in select volume on portal tables。
  • Watch for repeated 403s that may indicate broken auth flows after deploy。

4 . Keep secrets out of frontend environments。

  • Only public keys belong in browser code。
  • Service role credentials should live server-side only with narrow operational paths。

5 . Use least privilege across storage,functions,and integrations。

  • Give each integration only what it needs。
  • Remove unused webhooks,old API tokens,and stale service accounts。

6 . Add UX guardrails so users never see mixed-account state。

  • Clear cached portal state on logout。
  • Show account switch confirmation if your product supports multiple tenants per login。

7 . Track performance while fixing security。

  • Bad joins and overfetching can create both leakage risk and slow portals。
  • For client portals,I aim for p95 page API latency under 300 ms and Lighthouse scores above 85 once stabilized。

When to Use Launch Ready

This sprint fits best if you already have: 1 . A working Lovable plus Supabase prototype 2 . A live domain,or at least a staging URL 3 . Access to Supabase,Cloudflare,and your hosting account 4 . One person who can approve fixes quickly

What I handle inside Launch Ready: 1 . DNS,redirects,subdomains,Cloudflare,SSL,and caching setup 2 . Production deployment cleanup and environment variable review 3 . Secrets handling,monitoring,and uptime alerts 4 . Basic handover checklist so your team knows what changed

What you should prepare before booking: 1 . Supabase project access with owner-level permissions 2 . List of affected portals,tables,and file buckets 3 . Any recent screenshots of leaked data behavior 4 . Your current domain registrar login if deployment changes are needed

Delivery Map

References

1 . Supabase Row Level Security docs https://supabase.com/docs/guides/database/postgres/row-level-security

2 . Supabase authentication docs https://supabase.com/docs/guides/auth

3 . Supabase storage security docs https://supabase.com/docs/guides/storage/security/access-control

4 . roadmap.sh API Security Best Practices https://roadmap.sh/api-security-best-practices

5 . roadmap.sh Cyber Security https://roadmap.sh/cyber-security

---

Take the next step

If this is a problem in your product right now, here is what to do next:

  • [Use the free Cyprian tools](/tools) - estimate cost, score app risk, check launch readiness, or pick the right service sprint.
  • [Book a discovery call](/contact) - I will tell you honestly whether you need a sprint or if you can DIY the next step.

*Written by Cyprian Tinashe Aarons - senior full-stack and AI engineer helping founders rescue, launch, automate, and scale AI-built products.*

Next steps
About the author

Cyprian Tinashe AaronsSenior Full Stack & AI Engineer

Cyprian helps founders rescue, secure, deploy, and automate AI-built apps with production-grade engineering, launch systems, and AI integration.