Skip to content

Glossary / AI & Vibe Coding

AI & Vibe Coding

Row-Level Security (RLS)

Row-level security is a database rule set that decides which rows each user is allowed to read or write. Instead of the application deciding access, the database enforces it per row, so a user can only ever touch their own data even if the client is compromised.

CategoryAI & Vibe Coding
LevelIntermediate
Related serviceSaaS security check
Devoq ambient 3D sphere

What is row-level security (RLS)?

Row-level security is a database rule set that decides which rows each user is allowed to read or write. Instead of the application deciding access, the database enforces it per row, so a user can only ever touch their own data even if the client is compromised.

Key takeaways

  • RLS makes the database, not the app, decide which rows each user can touch.
  • The public anon key is safe only if RLS is on and every table has a scoped policy.
  • An app works identically whether RLS is on or off, so nothing in the demo warns you.
  • Deny by default; each policy must justify exactly which rows it exposes and to whom.

Why it matters

Modern app builders and backend-as-a-service platforms put a public key in the browser and rely on RLS to keep data safe. If RLS is off or misconfigured, that public key becomes a direct, unauthenticated door to your entire database. It is the single most common critical flaw in vibe-coded apps.

Common mistakes we see

The dangerous thing about RLS is that an app works perfectly whether it is on or off. Nothing in the demo tells you the door is open. We repeatedly find apps built on Supabase or Firebase where the developer assumed the anon key was a secret to protect, when in fact it is meant to be public and the actual protection, RLS or security rules, was never enabled. The result is that anyone who opens the browser console can read every row in every table. The second mistake is enabling RLS but writing a policy like "authenticated users can read" without scoping to the owner, which lets any logged-in user read everyone else data. Our approach is deny-by-default: every table starts locked, and each policy has to justify exactly which rows it exposes and to whom. Then we verify it the way an attacker would, from the client with the public key, before launch. If you cannot read someone else data with that key, the door is shut.

How RLS goes wrong

RLS never enabled

The developer treats the anon key as the secret and never turns on the actual protection, so anyone can read every row from the browser console.

Policy too broad

A rule like "authenticated users can read" with no owner scope, which lets any logged-in user read everyone else data.

Verify your RLS is real

  • RLS is enabled on every table, not just the obvious ones.
  • Each policy is scoped to the row owner, not just "authenticated".
  • You tested from the client with the public key and could not read another user data.
  • Storage buckets have their own rules, not just the tables.

Example

A booking app enables RLS but forgets a policy on the payments table. Because the default with RLS on is deny-all, payments silently stop loading. The opposite case, RLS off, is worse: every customer card detail is one console query away.

Check your app for backend exposure

Our free, passive SaaS security check detects backend config and flags the RLS risk, without touching your data.

Check your app for backend exposure

Frequently asked questions

Is my Supabase anon key a secret?
No. The anon key is meant to be in the browser. Your data is protected by row-level security policies, not by hiding that key. If RLS is off, the public key can read your tables directly.
How do I know if RLS is set up correctly?
Test it from the client with the public key and try to read another user data. If you can, a policy is missing or too broad. Our passive SaaS security check flags the exposure without reading your database.
Skip to content

Get In touch

Please fill in the form below.

    What do you need?

    We’re Here!

    US

    2108 N ST STE N SACRAMENTO, CA 95816

    Canada

    23 Mullen Drive Ajax, L1T2A9 Ontario, Canada

    India

    111, Platinum Plaza Opp. I.O.C. petrol pump, Bodakdev, Ahmedabad - 380054

    Follow us

    contactus background sape v1
    element 01
    element 02
    Skip to content
    Wait! Is Your Website Losing Customers?

    Get a free UI/UX audit and discover what’s holding your site back