Row Level Security (RLS) is the feature in Postgres, and therefore in Supabase, that decides which rows each caller may see or change. Turning it on is the first step. The second step is writing policies, and a policy can be written so that it lets everything through. That is what using (true) does.
What the policy looks like
A policy has a USING expression, which filters the rows a query may read or touch, and for writes a WITH CHECK expression. When the expression is true, every row passes for every caller the policy names. A policy for all to anon, authenticated using (true) with check (true) means: any visitor holding the app's public key may read, insert, update and delete every row. The table shows RLS as enabled in the dashboard. The effect is the same as having no RLS at all.
Builders and coding assistants often produce this shape when a first attempt at RLS breaks a page and the fastest way to get it working again is a policy that allows everything. The name is a clue: "Enable access for all users" or "allow all" are common.
Why the check you ran did not catch it
Supabase's defaults are on your side up to a point. Tables created in the dashboard get RLS enabled automatically, and tables created with SQL do not. Security Advisor, the built-in lint that runs in Studio and from the CLI, has an ERROR-level finding called rls_disabled_in_public. That one is quiet here, because RLS is enabled. The always-true policy is a separate finding, permissive_rls_policy, and it is a WARN. Warnings are easy to scroll past, and they can be dismissed in the dashboard. So a project can look clean at the error level and still expose every table.
A scan of 1,645 apps listed on Lovable's showcase found 170 with database endpoints readable without login, because RLS policies were missing or too broad, and the result was recorded as CVE-2025-48757 (Matt Palmer (Replit, Inc.), 2025). Two things belong next to that number. The researcher works at Replit, a competing builder, and Lovable disputes the CVE on the grounds that each customer is responsible for protecting their own data. Lovable's Publish flow also warns about tables without RLS, and Lovable Cloud runs on Supabase, so the policy check below applies to Lovable projects too.
The two-account test
Reading policies tells you what should happen. Testing tells you what does happen. You need two accounts in your own app and about fifteen minutes.
- Create account A and account B, and add one private record in each, such as a note, an order or a profile field.
- Sign in as A. In Chrome, right-click, choose Inspect, open the Network tab, and load the page that shows A's record. Click the request to
supabase.cothat returns it. - Remove the filter from the request. Supabase's REST API filters with query parameters like
?user_id=eq.<id>. Right-click the request, choose Copy as cURL, paste it into a terminal, delete the filter, and run it. If you would rather not use a terminal, ask your builder's chat to run the same table query without a filter while signed in as A. - Sign in as B in a private window and repeat step 2 with A's record id.
A bad result is any of these: A's unfiltered request returns B's rows, B can load A's record, or a request with no login at all returns rows from a table that holds private data.
Then read the policies directly. In the Supabase dashboard open Authentication, then Policies, and click each one. Look for true in USING or WITH CHECK on any table that is not meant to be public. Open Advisors, then Security Advisor, and read the warnings as carefully as the errors.
The fix
Replace using (true) with an expression that ties the row to the caller. The usual form is auth.uid() = user_id, where auth.uid() returns the signed-in user's id and user_id is the column that records the row's owner. Write separate policies for select, insert, update and delete rather than one for all policy, so a public read policy does not accidentally allow public writes. Keep true only for data that is meant to be public, and only for select.
If a table has no owner column, that is the first change: add one, fill it, and only then write the policy. Supabase's RLS guide covers the expressions and how to test policies with pgTAP through supabase test db. After the change, rerun the two-account test. Reading the new policy is not a substitute for watching B fail to load A's record.
The full pattern, with the code shape, our own test method and the fix direction, is at RLS policy that allows everything with using (true). Related shapes are RLS disabled on a table and Any signed-in user can read every row, where the policy checks that a caller is logged in but not who they are.
What to do this week
- Run the two-account test on every table that holds personal data: RLS policy using (true).
- Open Security Advisor and clear every warning, not only the errors: Supabase stack hub.
- If you build on Lovable, read the defaults and what Lovable's own tooling checks: Built with Lovable.