Supabase RLS

Get your Supabase RLS reviewed before user data leaks through the wrong policies

Row Level Security decides who is allowed to see which row. A single overly broad policy is enough for users to read other users' data. As a Supabase security audit, Veriploy reviews your Supabase RLS across tables, auth, storage and edge functions and keeps it under ongoing technical oversight afterwards, instead of stopping at a one-off look.

View packages
  • Baseline check 490 €
  • Policies + auth + storage
  • Reproducible tests
  • German point of contact
Timo Wevelsiep

Technical point of contact

Timo Wevelsiep

Software engineer, cloud architect, founder & managing director

I review code, security and infrastructure and surface what is technically risky before launch, customer use or due diligence.

For questions like:

  • Is this release ready for production?
  • Which CVEs are really critical?
  • Will the architecture carry the next users?
01

What Row Level Security in Supabase is

Row Level Security (RLS) is access control right inside the Postgres database. Instead of deciding in the frontend or the API who sees what, RLS policies define per table and per operation which rows a user may read or write. This is how it decides data separation:

01Policies apply at the row level, not just per table
02Separate rules for select, insert, update and delete
03Evaluation through auth.uid() and the request's JWT claims
04The anon key hits the same policies as logged-in users
05Without RLS enabled, a table is openly readable via the anon key
02

Why authentication is not the same as authorization

Authentication answers the question of who someone is. Authorization answers the question of what that person may see and change. Many Supabase projects solve the first part cleanly through Supabase Auth and assume the second part is handled too. It is not.

A valid login only means a request carries a real user. Whether that user can then reach another tenant's invoices, messages or files is decided solely by the RLS policy. If it is missing or too broadly written, every logged-in user, and in the worst case every anonymous request, sees more than intended.

That is exactly where our review starts: we check not only whether auth works, but whether authorization really holds per row and per operation, down to the policy condition itself.

03

Common RLS mistakes we find

RLS is powerful but easy to misconfigure. Tables created in raw SQL or via the SQL editor have RLS off by default, while tables created with the Table Editor have it on. These are the gaps we see most often:

MistakeWhat it leads to
RLS not enabledThe table is fully readable via the anon key, without any login.
Overly broad select policiesConditions like true or a missing user_id check expose every row.
Missing insert/update/delete limitsReads are protected, but users can write to foreign or arbitrary records.
Public storage bucketsFiles like uploads or receipts are retrievable without a storage policy.
service_role key in the wrong contextThe key bypasses RLS entirely and ends up in the frontend or is used in edge functions without their own auth and input checks.
Tenant ID only checked in the frontendTenant separation is easily bypassed through manipulated requests.
04

What Veriploy reviews in the RLS check

We walk the access chain systematically, from the table to the edge function, and rank every finding by severity. We review:

  • Tables: is RLS enabled everywhere user data lives
  • Policies: are select, insert, update and delete clean and not too broad
  • Auth: do auth.uid() and JWT claims behave as expected per role
  • Storage: are buckets and file policies protected against anonymous access
  • Edge functions: is the service_role key used only server-side and under control
  • Tests: reproducible checks that deliberately attempt anonymous and cross-tenant access
05

A concrete pattern: CVE-2025-48757

How real incomplete RLS gets is shown by CVE-2025-48757. In May 2025 a security researcher documented that more than a hundred apps built with a low-code tool had Supabase tables readable, and partly writable, via the public anon key without any login. The vulnerability was rated critical per the CVE record (CVSS 9.3), in the Incorrect Authorization category.

An important note for context: this was not a bug in Supabase itself. The cause sat in the configuration of the generated apps, missing or overly broad RLS policies on tables whose RLS was off by default. Supabase provides RLS, but whether it correctly holds per table and operation is decided by the individual app.

This exact pattern, automatically generated code plus assumed but unverified data separation, is why we do not tick RLS off once but keep it under ongoing oversight. Every new table and every changed policy can soften the separation again.

Example finding

What a finding looks like

veriploy-reportCritical
RLS-01Row Level Security

RLS for the messages table is not enabled, contents are readable via the anon key without any login. Recommendation: enable RLS and enforce a select policy on auth.uid() = user_id.

Comparison

One-off look at the RLS or ongoing oversight?

One-off lookVeriploy ongoing
TimingPoint-in-time snapshot on a fixed dateContinuous, with every new table and policy
New tablesNot covered, RLS often stays offNew tables without active RLS surface early
Policy changesNot re-checkedOverly broad changes are flagged
Storage and edge functionsRarely includedBuckets and service_role usage in view
AssessmentA list at the endHuman prioritisation, not just a score
FAQ

Frequently asked questions

  • Is it not enough that Supabase Auth is active?

    No. Auth only clarifies who is logged in. Which rows that user may read or change is decided by the RLS policy. Without active and correctly limited policies, a logged-in or even anonymous request can see more than intended. We check exactly this authorization per table and operation.

  • Do you also check storage buckets and edge functions?

    Yes. The RLS review does not stop at the tables. We check whether storage buckets and file policies are protected against anonymous access and whether the service_role key is really used only server-side and under control, not in the frontend or unprotected in edge functions.

  • Do you fix the policies yourselves?

    Not within the plan. We review, prioritise and explain which policy is missing or too broad and how it should look. Implementation runs through your team or separately through Wevelsiep Advisory or WZ-IT. That keeps the review independent from the implementation.

  • What do you need for the review?

    Read access to the repository and insight into the database schema including its policies. We do not need write access to the production database. For the reproducible tests, a test or staging environment is usually enough.

  • What does a Supabase RLS review cost?

    The entry point is fixed: Snapshot 249 € and Baseline 490 € as one-off reviews, the RLS review is part of the Baseline check. Ongoing oversight starts at 299 € per month (Watch), then Guard at 749 € and Launch at 1.490 € per month. All prices are net plus VAT, plans cancellable monthly.

  • What does CVE-2025-48757 have to do with this?

    This case shows how real incomplete RLS gets: more than a hundred low-code apps had tables readable via the anon key without any login, rated critical per the CVE record (CVSS 9.3). The cause was misconfiguration, not a Supabase bug. This is exactly the pattern we review and keep under ongoing oversight.

Supabase RLS review in the Baseline check, before data leaks.

Start with the Baseline check and keep policies, storage and edge functions under ongoing oversight afterwards.

View packages