Skip to content
BuildThenTestedSee packages
CriticalData access

RLS policy that allows everything with using (true)

The table looks protected in the dashboard, yet any visitor with the public anon key can read, insert, update and delete every row. Rules that decide which user can read or change which rows in the database. Check it yourself with the steps below; our test adds what a script and a second account can find.

What it looks like

alter table public.profiles enable row level security;

create policy "Enable access for all users"
  on public.profiles
  for all
  to anon, authenticated
  using (true)
  with check (true);
Row Level Security is switched on, but the only policy says every row passes for every role, which is the same as having no RLS.

What happens

The table looks protected in the dashboard, yet any visitor with the public anon key can read, insert, update and delete every row.

Where it shows up

Descriptive, not a verdict: builders and stacks whose defaults make this reachable, or that a public incident names. Each hub states the tool's own security features.

Seen in public

A scan of 1,645 Lovable-built apps found 170 (about 10.3%) with database endpoints readable without login because Supabase row-level security policies were missing or too broad; recorded as CVE-2025-48757, CVSS 9.3.

  • 1,645 Apps scanned
  • 170 Apps with inadequate RLS
  • 10.3% Share of scanned apps
  • 303 Exposed endpoints
  • 9.3 Critical CVSS 3.1 base score (CVE record)
  • 8.26 Researcher's own CVSS base score
  • 2025-03-21 Scan date
  • 2025-05-29 Public disclosure

May 2025 · Matt Palmer (Replit, Inc.) · all sources

Check it yourself

Uses your builder's dashboard and your browser. No tools to install.

  1. In the Supabase dashboard open Authentication, then Policies. Row Level Security (RLS) is the per-row access rule set Postgres applies to each query, and this page lists every policy per table.
  2. Click each policy and read the USING and WITH CHECK expressions. Look for true, or for names like Enable access for all users or allow all.
  3. Open Advisors, then Security Advisor, and look for the finding Permissive RLS Policy.
  4. A bad result is a policy on a table with private data whose expression is true for anon or authenticated, especially for insert, update or delete.

What we check

We read every policy expression from the database catalog and then test each table as an anonymous visitor and as two unrelated signed-in users, confirming whether user A can read or change user B's rows. The report pairs each permissive policy with the rows it exposed.

Fix direction

Replace using (true) with a condition that ties the row to the caller, such as auth.uid() = user_id, and keep true only for data meant to be public and only for select. Supabase's documentation says the same, and its Security Advisor flags always-true policies after each change.

Mechanism documented in: Row Level Security (verified 2026-09-21); Database Advisors (verified 2026-09-21).

Covered by

Pre-launch check ($490, 48 hours) and Security sweep ($290, 24 hours)

Both include a re-check after your fixes.

Compare packages

Related patterns

  • Row Level Security disabled on a tableData access

    Anyone with the project URL and the public anon key, both of which sit in the app's JavaScript, can read, edit or delete every row in the table.

    Critical
  • Any signed-in user can read every rowData access

    Anyone who creates a free account can page through every other customer's records, which is a data breach with a sign-up form as the only step.

    Critical
  • Inverted policy logicData access

    Signed-out visitors or other customers can read rows meant for one account, while the owner sees an empty page and nobody notices.

    Critical
  • Record ids accepted without an ownership checkData access

    Anyone who changes the id in a URL or request can read, edit or delete another customer's record.

    Critical

Questions

what does using true mean in a supabase policy

The USING expression decides which existing rows a query may see or touch, and true means every row passes. Supabase's documentation describes a policy with to anon using (true) as granting unauthenticated visitors read access to all rows and says to use it only for data meant to be public. For private data, the expression should compare the row to auth.uid().

is rls enabled with a permissive policy still protecting my data

No. Enabling RLS only makes Postgres consult the policies; a policy that always returns true then lets everything through. The table shows as protected in the dashboard while behaving as if RLS were off. The Security Advisor lists this as a Permissive RLS Policy finding.

how do i write a supabase rls policy for user owned rows

Create separate policies per operation. For select, use using (auth.uid() = user_id); for insert, use with check (auth.uid() = user_id); for update, use both. Grant them to the authenticated role only. Then sign in as two different test accounts and confirm each sees only its own rows.

Back to the catalogue, or run the self-check for your stack.