Row level security (RLS) is the set of rules inside your Supabase database that decides which rows each visitor can read, add, change or delete. In a typical AI-built app the browser talks to the database directly, so RLS is often the only thing standing between a stranger and your users’ data. If it is switched off, or switched on with a rule that is too loose, anyone with your app’s public key can query your tables. This guide explains how it works in plain English and how to test yours.
Why does Supabase depend so much on RLS?
Supabase lets your website talk to the database without a server in between. That is why AI app builders such as Lovable use it: it is fast to set up and there is less code to write.
The trade-off is that your website has to carry a key to reach the database, and anything in a website can be read by anyone. Supabase’s answer is that the publishable key is safe to ship because “it only reaches what Row Level Security allows” (Supabase API keys docs). Put the other way round: the public key is only as safe as your RLS rules.
Supabase’s own guidance is to “enable RLS on every table in an exposed schema”, and it warns that without RLS such a table is readable and writable by any role that has been granted access to it (Supabase RLS docs).
What has gone wrong in AI-built apps?
The best-documented case involves Lovable. A researcher, Matt Palmer, found that a Lovable-built site let anyone pull full user records by tweaking database queries. A follow-up scan found 303 endpoints across 170 projects without proper RLS, exposing names, emails, phone numbers, payment status and API keys (Superblocks, 2025). The issue was recorded as CVE-2025-48757, which Lovable disputes on the basis that each customer is responsible for their own app’s data (SentinelOne).
Wider samples point the same way. In a May 2025 sample of 1,645 Lovable-built apps, 170 let anyone access personal information, and the same reporting says about 70% of Lovable apps had RLS disabled entirely (The Next Web, 2026).
The problem is not unique to one tool. Any AI assistant that creates tables quickly, then adds a permissive rule to make an error go away, can produce the same result.
What are the common RLS mistakes?
We see four patterns again and again.
RLS switched off on some tables
The main tables get rules, but a table added later, perhaps for messages, invoices or uploaded documents, does not. Supabase notes that on existing projects, new tables in the public schema start with privileges granted to the anon and authenticated roles, and it points to event triggers as a way to switch RLS on for every new table automatically (Supabase RLS docs).
RLS switched on with a rule that allows everything
A rule such as “allow read where true” turns RLS on in name only. AI tools sometimes write this when a page fails to load. Note that a scanner which only checks whether a policy exists will not catch it: Lovable’s early security scan was criticised because it “only flagged the presence of RLS, not whether it worked” (Superblocks, 2025).
Rules that forget logged-out visitors
A rule that compares the owner of a row with auth.uid() (the ID of the person making the request) looks correct. But for a logged-out visitor, auth.uid() returns null. Supabase recommends writing the check explicitly as auth.uid() IS NOT NULL AND auth.uid() = user_id so the intent is clear (Supabase RLS docs).
The secret key used in the browser
Supabase’s secret key, and the older service_role key, bypass RLS completely. If an AI tool puts it in browser code to “fix” a permissions error, every rule you wrote stops mattering. Supabase says it should never go “in a browser, a shipped application, or source control” (Supabase API keys docs). Our post on exposed secrets in AI-built apps explains how to check for this and what to do if you find it.
How can you test your own RLS?
You can do the first two checks without an engineer. The third needs someone comfortable with the database.
- Look at the dashboard. In the Supabase dashboard, find where your tables and their policies are listed. Every table that holds user data should show RLS as enabled and list at least one policy. Write down any that do not.
- Read each policy in plain words. For each table, ask: who can read a row, who can add one, who can change one, who can delete one? If the answer to any of these is “anyone” and the table holds personal data, that is a finding.
- Test from the outside. Have an engineer call the database API with only the publishable key and no login, then again logged in as test user A trying to read user B’s rows. Both should return nothing that does not belong to the caller. This is the test that matters, because it checks what the rules actually do rather than what they say.
Repeat the third test after every significant change. AI tools can rewrite policies as a side effect of an unrelated request.
Can’t you just ask the AI tool to fix it?
You can ask, and it may help, but treat the answer as a draft. The same habit that created the problem, making an error disappear as quickly as possible, can produce a fix that looks right and is not. A policy that checks the wrong column, or one that lets any logged-in user read every row, will pass a quick click-through and still leak data.
Two rules keep this safe. First, have a person who understands the data model read every policy change before it goes live. Second, re-run the outside-in test from the previous section after each change, because a policy is only correct if it blocks the requests it should. “The tool says RLS is enabled” is not the same as “a stranger cannot read our users’ data”.
What does a good RLS set-up look like?
A sound set-up for a typical app has a few properties:
- RLS is on for every table in the exposed schema, with new tables switched on automatically.
- Each table has separate policies for reading, inserting, updating and deleting, rather than one rule for everything.
- Policies tie rows to the owner, an organisation or a role, and check that the user is logged in.
- The secret key only ever runs on a server or in a server function.
- Someone re-runs the outside-in test whenever the schema changes.
If RLS was off, what else should you do?
Fixing the rules stops future exposure. It does not tell you whether someone already took the data. Check your Supabase logs for unusual reads, rotate any keys that were stored in exposed tables, and take advice on whether you need to notify users. In India, the DPDP Rules 2025 set out breach reporting to the Data Protection Board and to affected people, with those duties phasing in by May 2027 (AMS Shardul, 2025).
It is also a good moment to confirm you can restore your data if it was changed; see our guide to backup and restore testing for small apps. RLS is one item on our production readiness checklist for vibe-coded apps, and the other eleven are worth a look too.
Want us to check it?
Our free production check tests your RLS from the outside, the way an attacker would, and covers secrets, backups, environments and privacy. You get a call, a written report and a quote, and a named engineer approves every fix. More on how we work with AI-built apps.