Guide · AI-built apps

Supabase security for non-developers

If Lovable or Bolt built your app on Supabase, this is what keeps your data private, and how to check it yourself in about half an hour.

Rob Sherwood, co-founder of Dev Partners
The short answer: your app's front end talks to Supabase directly with a key that is meant to be public, so the only thing protecting each table is its Row Level Security rules. Open the Security Advisor in your Supabase dashboard: any table flagged "RLS disabled in public" can be read and changed by anyone, and policies flagged as allowing unrestricted access protect very little.

Supabase is a good choice, and it's what most AI app builders reach for when your app needs a database and logins. It's secure when it's set up properly. The trouble is that "set up properly" depends on a handful of settings the AI may or may not have got right, and you can't tell by using the app.

This guide explains the five things that matter, in plain English, and how to check each one in your own dashboard. Everything here is from Supabase's own documentation, linked as we go, because these tools change quickly.

Your app talks to the database directly

In a traditional app, the browser talks to a server you control, and the server decides what each person is allowed to see. In most Supabase apps built by AI tools, the browser talks to the database itself, using a key that's built into the page.

That's by design, and it's fine, as long as the database knows who's asking and what they're allowed to touch. That job belongs to Row Level Security. If it isn't doing the job, the public key in your page is effectively a key to the whole table.

What Row Level Security is, and what "RLS disabled" means

Row Level Security (RLS) is a set of rules attached to each table that decide which rows a given user can read, add, change or delete. Supabase describes each policy as working like an extra condition added to every query on that table.

The important bit: Supabase's docs say a table in an exposed schema without RLS is readable and writable by any role with a grant on it. On most projects that includes visitors who aren't logged in. So a customers table with RLS off can be read by anyone who has your app's public key, which is anyone who has loaded your app.

Once RLS is on, the reverse is true: nothing is reachable with the public key until you add policies that allow it.

How to check

  1. In your Supabase project, open Advisors and then Security Advisor.
  2. Look for the error "RLS disabled in public" (Supabase's wording: "Table publicly accessible"). Each one is a table anyone can reach.
  3. Also look for "Security policy not enforced", which means policies were written but RLS was never switched on, so they do nothing.
  4. In the Table Editor, each table shows whether RLS is enabled. Every table your app uses should say it is.

Policies that are switched on but let everyone in

This is the one AI tools get wrong most often, because an over-generous policy makes an error go away and the app starts working.

A policy with using (true) means "every row, for everyone this policy applies to". Supabase's docs say to use that only for data that is meant to be public, such as a list of products. On a table of orders, messages or profiles it means every user can read every other user's records.

Two other patterns to watch for:

  • "Any logged-in user" policies. Checking only that someone is signed in stops strangers but lets every customer see every other customer's data.
  • Policies based on user-editable data. If a policy decides someone is an admin from information the user can change about themselves, they can make themselves an admin. Supabase's advisor calls this "Security policy relies on user-editable data".

How to check

  1. In the Security Advisor, look for "Security policy allows unrestricted access" and "Security policy relies on user-editable data".
  2. Open Authentication then Policies and read each table's policies. For anything personal, the policy should compare the row's owner with the logged-in user, not just allow everyone.
  3. Do a real test: create two test accounts, add a record as one, and see if the other can see it.

Publishable keys, secret keys, and the old names

Supabase has two kinds of key, and it renamed them recently, so tutorials and AI tools use both sets of names:

  • Publishable key (starts sb_publishable_), which replaces the old anon key. Supabase says it's safe to expose online, in your web page or app. It only gets what your RLS policies allow.
  • Secret key (starts sb_secret_), which replaces the old service_role key. Supabase is blunt: it "bypasses every Row Level Security policy you have". It must only ever be used on a server you control.

The old keys are long strings starting eyJ. They still work alongside the new ones, and Supabase says they're being deprecated by the end of 2026, so it's worth moving over and then switching the old ones off in Settings, API Keys.

How to check

  1. Ask whoever built the app, or search the code and the GitHub repository, for service_role and sb_secret_.
  2. Either should only appear in server-side code such as Edge Functions, read from a secret setting, never typed into the code itself.
  3. If a secret or service_role key has ever been in front-end code or a public repository, treat it as leaked: create a new one and revoke the old one. Deleting it from the code isn't enough.

File storage buckets

Uploaded files live in Storage buckets, and access to them is controlled by policies on the storage tables, in the same way as your other data. A bucket marked public is readable by anyone with the link, which is fine for product photos and not fine for passports, contracts or invoices.

How to check

  1. Open Storage and note which buckets are public.
  2. Anything private or personal should be in a private bucket, with policies limiting each user to their own folder, and files shared through links that expire.
  3. In the Security Advisor, look for the warning about a public bucket that allows listing, which means someone can see the list of files as well as fetch them.

Login settings, and functions that skip the rules

Login settings

Under Authentication settings, check:

  • Confirm email, in the email provider settings. With it off, anyone can sign up with an address they don't own.
  • Allow new users to sign up. If your app is invite-only or staff-only, this should be off, or anyone can create an account and get whatever "logged-in users" can see.
  • Password strength. Supabase recommends a minimum of 8 characters and lets you require mixed character types. Leaked password protection, which rejects passwords known from breaches, is available on the Pro plan and above.

Security definer functions

Database functions normally run with the permissions of whoever calls them. A function marked security definer runs with the permissions of whoever created it, which on Supabase is usually an account that bypasses RLS. Supabase's docs say such a function can return rows the caller isn't allowed to read, and by default anyone can call it, including people who aren't logged in.

AI tools write these to get round an RLS error. Sometimes that's the right fix; often it quietly undoes your security. The Security Advisor warns when a security definer function can be run by signed-out or signed-in users, and when a function's search path isn't fixed.

Backups

Not strictly security, but it's what saves you if something goes wrong. Supabase's free plan doesn't include daily backups; Pro keeps 7 days, Team 14 and Enterprise up to 30, and point-in-time recovery is a paid add-on. If you're on the free plan with real customer data, export it regularly and keep a copy somewhere else. Whatever plan you're on, try restoring one before you need to. Our guide on testing your backups covers how.

Hire Supabase developers, a Supabase consultant, or a Supabase agency?

If you would rather someone else went through all this, there are three routes, and they suit different jobs.

Supabase's own experts list. Supabase keeps a directory of agencies and developers with specialist experience on the platform, at supabase.com/partners/experts. If you are building something new and want a Supabase agency that lives in the platform, start there.

Freelance marketplaces. Upwork, Fiverr and Contra all let you hire Supabase developers by the hour. Fine for a well-defined task; check their past work, and keep the project and its keys in your own account.

An independent review. That is us. We are not an official Supabase partner and we would not call ourselves a Supabase consultant in that sense. We are developers who build with AI every day, and most of the Supabase projects we see were set up by Lovable, Bolt or a similar tool. We read every table's policies, the functions, the storage rules and the code that calls them, then fix what is wrong or tell you exactly what to fix. The code, the project and the keys stay yours throughout. Our guide to hiring a developer to finish your AI app has the questions to ask whoever you choose.

Want a developer to go through it with you?

Our AI Code Audit is a fixed-price written review of an AI-built app. For Supabase projects that means reading every table's policies, the functions, the storage rules and the code that calls them, and telling you in plain English what to fix first.

What people ask about Supabase security

Open the Security Advisor in your Supabase dashboard and deal with anything marked as an error first, especially "RLS disabled in public". Then read each table's policies, check which storage buckets are public, check your login settings, and make sure the secret (service_role) key never appears in front-end code.

Rules attached to each table that decide which rows each user can read, add, change or delete. Because most Supabase apps talk to the database straight from the browser using a public key, RLS is what stops one user reading another's data, or a stranger reading all of it.

Yes, the anon key (now called the publishable key) is designed to be public, but only because Row Level Security limits what it can do. If a table has RLS off or a policy that allows everyone, the public key can reach that data. The service_role key (now the secret key) is never safe to expose.

It runs automatic checks on your project and flags issues such as tables with RLS disabled, policies that exist but aren't enforced, policies that allow unrestricted access, views and functions that bypass RLS, and public storage buckets that can be listed. It's a good first pass, but it can't tell whether your policies match your business rules.

In our experience: tables with RLS switched off, policies that let every user see every row, the secret key used in front-end code, security definer functions written to get round an error, public storage buckets holding private files, and open sign-up on apps that should be invite-only.

Not sure what the Security Advisor is telling you?

Send us what it says and what your app does, and we'll tell you which bits matter.

Plenty of warnings are fine for your situation. A few really aren't. We'll tell you which is which.

What we will cover:

  • Which advisor warnings matter for your app
  • Whether your policies match how the app is used
  • What a proper review would cover

Rather talk now? Book a call or ring 01474 639 089.

We reply within one working day.

Get in touch