Skip to content
Shpatik.
AI code· 24 Jul 2026· 6 min read

Supabase Row-Level Security: The Silent Vibe-Code Vulnerability

You built something real with Lovable or a similar AI app builder. It has a login screen, a database, a working product. It looks finished. Underneath, there is a decent chance any signed-in user, or nobody at all, can read every row in every table. Not because you did something wrong, but because the default was left where the AI builder put it.

This is Row-Level Security, and it is one of the most common serious vulnerabilities we find in vibe-coded apps.

The short answer

  • Row-Level Security (RLS) is a Postgres feature that controls which rows a database query is allowed to touch, per user.
  • Supabase, the backend Lovable and similar AI builders generate on, ships RLS off by default on every new table.
  • AI builders like Lovable generate the schema and the UI fast, but rarely turn RLS on or write correct policies, because doing so requires knowing your data model and your access rules, not just your prompt.
  • Without RLS, your API keys are often enough on their own for a stranger to read, edit, or delete any user's data, directly, no login required.
  • You can get a rough gut-check yourself in a few minutes by opening your Supabase dashboard and checking the RLS column on each table.
  • A confident answer needs someone to actually test the policies, not just check that they exist.

What Row-Level Security actually is

A normal database table has no concept of "whose row is this." If your app's server asks for every row in the invoices table, Postgres hands over every row in the invoices table. It trusts the query.

Row-Level Security changes that contract. When RLS is turned on for a table, Postgres itself starts filtering every query against rules you define, called policies. A policy might say "a user can only select rows where user_id matches their own ID." Once that policy exists and RLS is enabled, it does not matter what the application code asks for. The database enforces the boundary itself, underneath the app.

This matters specifically because of how Supabase works. Supabase gives your front end a public API key so your browser can talk to the database directly, without a custom backend server sitting in between. That is a large part of why AI builders can generate a working app so quickly. But it also means the database is the only thing standing between a visitor and your data. If RLS is off, that public key is effectively a master key. Anyone who opens your browser's network tab, copies the key, and sends their own request gets whatever is in the table.

Why RLS is opt-in, not automatic

Supabase turns RLS off by default when you create a table. This is a reasonable engineering decision on their part, not a bug. RLS is off by default because Supabase cannot know your access rules in advance. Should a user see only their own orders, or their team's orders, or orders in their region? Should an admin role see everything? Every app answers this differently, so Supabase leaves the table open until you tell it otherwise, and expects the person building the app to close it deliberately.

That expectation is where AI builders run into trouble. A tool like Lovable is optimized to get you from a prompt to a working screen. Turning on RLS and then writing the correct policy for every table, every role, and every relationship is a separate, careful step that requires understanding your specific data model, not just describing a feature. It is easy for that step to get skipped, or done partially, and the app keeps working perfectly in every test you personally run, because you are logged in as yourself with legitimate access to your own data. The gap only shows up when someone else looks.

This is why RLS issues are silent. There is no error message. No warning banner. No broken button. The demo works. The first users sign up without incident. The vulnerability sits there, invisible, until someone curious or malicious tries a direct request instead of clicking through your UI.

How a founder can get a rough gut-check

You do not need to read code to get a first read on this. A few minutes in your Supabase project will tell you a lot.

  • Open your Supabase dashboard and go to the Table Editor. Each table has an RLS toggle. If it says "RLS disabled," that table has no row-level protection at all, and your public key can likely read or write everything in it.
  • If RLS shows as enabled, click into the policies for that table. An empty policy list with RLS "enabled" is its own trap: some Supabase configurations default to denying everything with no policies, which breaks your app, so builders sometimes add a wide-open policy like "true" to make it work again, which is functionally the same as RLS being off.
  • Pay closest attention to tables holding anything sensitive: user profiles, payment or subscription records, messages, uploaded files, anything with another user's personal data in it.

This gives you a rough signal, not a verdict. A table can have RLS enabled and policies present and still be wrong, for example a policy that checks the right column but with the wrong comparison, or one that forgets a role entirely. Confirming that requires someone to actually attempt the access a real attacker would attempt, not just confirm a checkbox is ticked.

What to do if you are not sure

If you turned on a few toggles and everything now says "RLS enabled," that is a good sign but not a clean bill of health. If it says "disabled" on anything holding real user data, treat that as urgent, not a someday task.

Either way, the safest move is to have someone who did not build the app look at it with fresh eyes. A code audit gives you a clear, written picture of where your Supabase setup and the rest of your app stand, including RLS specifically, without committing you to a rebuild. If you already know Lovable is where you built this and want the fastest path to a straight answer, our Lovable fix page walks through exactly what we check first. And if the audit turns up real gaps, vibe-code cleanup is the work of closing them properly while keeping everything you already built. You can also see what this kind of review actually looks like in a sample audit report before you commit to anything.

Key takeaways

  • RLS is the mechanism that makes a Supabase-backed app safe when the front end talks to the database directly.
  • It is off by default, on purpose, because Supabase cannot guess your access rules for you.
  • AI builders generate working screens fast but often leave RLS off or shallow, and nothing in the demo will tell you.
  • You can spot an obvious "RLS disabled" table yourself in the Supabase dashboard in a few minutes.
  • Confirming your policies are actually correct, not just present, needs a second set of eyes.

A calm next step

If you built your app with Lovable or another AI builder and you have never specifically checked your Supabase RLS settings, that is worth checking this week, not someday. If you want a straight, written answer rather than a guess, start with a free written first read: tell us what you built and what worries you, we will tell you honestly what we find. Look at a sample audit report to see the format, or read our Lovable-specific breakdown of what tends to go wrong.

Recognise the problem?

If any of this sounds like your project, let's talk.

A free written first read and a clear next step. No obligation.

Not ready to send anything? See a sample report first.

  • You keep all code & access — always
  • NDA on request, before you share anything
  • Free, no-obligation first read