Guide

Is my Lovable app secure? A pre-launch Supabase RLS checklist

Last checked 19 Oct 2026 · 5 min read · by Ship Weekend

Short answer: if your app talks to Supabase from the browser, as most Lovable and Bolt apps do, your database is reachable by anyone who opens DevTools. That's normal and by design. What keeps it safe is Row Level Security (RLS) plus correct grants. Supabase's own docs say a table in an exposed schema without RLS is readable and writable by any role with a grant on it.¹ So before launch: turn on RLS for every table, write a policy for each operation, revoke grants you don't need, keep secret keys off the browser, and test while signed out.

This isn't scaremongering. It's one of the best-documented real problems in AI-built apps (see the CVE below), and you can usually fix it in an afternoon.

Why this happens in vibe-coded apps

Tools like Lovable generate front-ends that call the database directly using a publishable (formerly anon) key. Supabase states plainly that this key is public: anyone can read it from your site's code.² That's fine as long as RLS decides what each request can see.

When RLS is missing or too loose, strangers can read or change data. That isn't hypothetical. CVE-2025-48757 (May 2025) documented Lovable-generated projects exposing data, including emails and payment status, through missing or insufficient RLS.³ The fix the write-up recommends is exactly the checklist below.³

Lovable's publish-time security scan helps, but per the CVE write-up it checks that RLS policies exist, not that they match your app's logic.³ You still need to look.

The checklist

1. RLS is enabled on every table in an exposed schema

In the Supabase dashboard, go to Table Editor: each table shows whether RLS is on. Tables created in the Table Editor have RLS on by default, while tables created with SQL may not.³ Fix:

alter table public.your_table enable row level security;

Supabase's Security Advisor flags common problems like this, so read every finding before dismissing it.² ⁴

2. Grants are no broader than your app needs

This is the one most people miss. Postgres checks grants first, then policies. On many existing projects, a new table in public automatically grants select, insert, update, delete to anon and authenticated, and adding policies doesn't take those grants back.¹ If signed-out visitors should never write to a table, revoke it:

revoke insert, update, delete on public.your_table from anon;

(Grant only what each role needs. See Supabase's Securing your API.⁵)

3. One policy per operation, tied to the user

Write separate policies for select, insert, update and delete. The standard ownership pattern from Supabase's docs is:¹

create policy "Users can view their own rows"
on public.your_table for select
to authenticated
using ( (select auth.uid()) = user_id );

For insert and update, also add a with check clause so users can't write rows that belong to someone else.

4. No using (true) on anything sensitive

to anon using (true) means every signed-out visitor can read every row.¹ That's right for genuinely public content, like published blog posts. It's wrong for users, orders, messages or anything with an email address in it.

5. Sensitive columns live in their own table

RLS works on whole rows. If a row mixes public and private data (say, a username and a payment status), anyone allowed to read the row reads both.³ Split private fields into a separate table with stricter policies, or serve them through a server function.

6. Views don't leak around your policies

Views bypass RLS by default, because they're usually created by the postgres role (security definer).¹ A view over a protected table can hand out every row. Follow Supabase's "Expose a view safely" guidance¹, or don't expose the view at all.

7. Secret keys never reach the browser

Heads-up: Supabase is deprecating the legacy anon and service_role keys by the end of 2026 in favour of publishable and secret keys. Creating new keys doesn't disable the old ones, which is a separate step.²

8. No third-party secrets stored in client-readable tables

API tokens for other services (OpenAI, Google Maps and so on) shouldn't live in a table your front-end can read. Keep them in server-side secrets (e.g. Edge Function secrets) and call those services from the server.³

9. Storage buckets have policies too

Supabase Storage uses the same policy system. Check that private uploads (avatars, invoices, documents) aren't in a public bucket and that the bucket policies match your app.

10. You've actually tested it as a stranger

This is the step that matters most. Supabase recommends writing tests that assert allow and deny for every operation, as both anon and authenticated, and running them with supabase test db.¹ The low-tech version: 1. Open your live site in a private window, signed out. 2. Open DevTools → Network and use the app. Look at the requests to *.supabase.co/rest/v1/…. 3. Ask yourself whether anything there should be private. If you can see it, so can anyone. 4. Sign in as user A, create something, then sign in as user B and try to see or edit it.

FAQ

Is it safe that my Supabase key is visible in my site's code? Yes, if it's the publishable (or legacy anon) key and RLS and grants are set correctly. That key is designed to be public.² The secret/service_role key is never safe to expose.²

Is Lovable secure? Lovable's platform runs your app's hosting and backend, but whether your app's data is protected depends on your RLS policies and grants, which are specific to your app. Use the checklist above, and don't rely on any scanner alone.³

I turned on RLS and now my app shows nothing. What happened? That's RLS working: with no policy allowing access, queries return no rows. Add the policies your app needs (step 3). If you get a permission error (42501) instead, a grant is missing, so check grants before changing policies.¹

Do I need to do this if my app has no login? Yes, arguably more so, because every visitor is anon. Make sure anon can only read what's meant to be public and can't write anywhere it shouldn't.


Want a second pair of eyes? The £39 Launch Check tests (with your permission) whether anonymous visitors can read your tables, looks for exposed keys on your live site and in a public repo, and gives you a prioritised, plain-English fix list with copy-paste prompts for Lovable, Bolt or Cursor. We never ask for your database password or keys.

Sources

  1. Supabase docs, Row Level Security: https://supabase.com/docs/guides/database/postgres/row-level-security
  2. Supabase docs, API keys: https://supabase.com/docs/guides/api/api-keys
  3. Matt Palmer, CVE-2025-48757 (29 May 2025): https://mattpalmer.io/posts/2025/05/CVE-2025-48757/
  4. Supabase docs, Advisors: https://supabase.com/docs/guides/observability/advisors
  5. Supabase docs, Securing your API: https://supabase.com/docs/guides/api/securing-your-api