Tell Me When Down
How it worksWhat we checkPricing
BlogFree toolsCompareDocs
Log inGet started
All posts
Security for vibe-coded apps

Is my Supabase database public? RLS, and how to check

July 18, 2026·6 min read
A glowing neon "OPEN" sign in the dark — a database left open to anyone who holds the public key.

Here's the uncomfortable test: open your app, view source, and copy the Supabase URL and anon key sitting right there in the page. Anyone can. The only question that matters is whether those two public values let a stranger read your entire database — and for a lot of AI-built apps, the answer is yes.

"Is my Supabase database public?" has a precise answer, and it comes down to one feature being on and configured correctly. Let's check yours.

Why the public key is supposed to be safe

The anon key is public by design. It's meant to be in the browser. Supabase's security model never relied on hiding it — it relies on Row Level Security, database rules that fence off which rows each request is allowed to see. RLS is the lock; the anon key is just a key everyone's allowed to hold.

Turn RLS off and the fence is gone. That public key now reads and writes every row in the table — every user's email, every private record — straight from anyone's browser. The app still works perfectly, which is exactly why nobody notices.

The trap: created outside the Table Editor

Supabase turns RLS on automatically only when you create a table through its Table Editor. Create one any other way — raw SQL, a migration, or an AI tool writing your schema — and RLS is off by default. Since AI builders write a lot of schema, this is the single most common way an app ships with public tables.

The subtler trap: RLS on, still public

This is the one that fools people who think they're safe. You can enable RLS and still be wide open if the policy allows everyone. A policy of USING (true) reads as "this rule matches every row" — which is the same as no protection at all.

"RLS enabled" is not the finish line. RLS enabled with a real, restrictive policy is. A dashboard that says RLS is on tells you the lock exists — not that it's actually locked. Check the policy, not just the toggle.

Check every table properly

  1. Enable RLS on every table in the public schema. Assume anything not made in the Table Editor is off until you've confirmed otherwise.
  2. Read each policy and check it actually ties rows to a user — auth.uid() = user_id — rather than letting everyone through.
  3. Test as an anonymous user. Query the table with just the anon key and see what comes back. If you get rows you shouldn't, so does everyone else.

This prompt does the whole audit, including the USING(true) trap:

paste into Claude or ChatGPT
Check whether my Supabase database is publicly readable, and fix it. Be blunt.

1. List every table in the public schema and tell me, for each, whether Row Level Security is ENABLED. Flag every table with RLS off — those are readable/writable by anyone who has the anon key (which is public).
2. For every table with RLS ON, show me its policies and tell me plainly whether they actually restrict rows to the owning user (e.g. auth.uid() = user_id) or whether a policy is effectively "allow everyone" — including the USING(true) trap where RLS is on but the policy lets everybody through.
3. Point out any table created via SQL, a migration, or generated code rather than the Table Editor, since those don't get RLS enabled automatically.
4. For each problem table, give me the exact SQL to enable RLS and add a correct, restrictive policy.

Assume an attacker already has my anon key and my project URL — because they do.

Supabase's Row Level Security guide has the policy syntax. This is the exact gap behind the 2025 Lovable disclosure, and it sits inside the broader how to secure a Supabase app checklist.

Lock it, then watch what you can't see

RLS is a fix you apply once and then can't observe — nothing in the running app tells you a later migration quietly added a table with RLS off. The database side is on you to audit; the outward-facing side is where continuous monitoring helps.

Tell Me When Down watches your app from outside — the certificate, the uptime, the endpoints — so once you've closed the RLS gap, a different kind of change doesn't slip past you unnoticed.

Close the public-database gap, then keep an eye on the rest.

The audit above tells you if your Supabase data is exposed today. Tell Me When Down watches everything on the outside after — SSL, uptime, endpoints — free, no card, so the next quiet change reaches you first.

Watch my appfree · no card required
more on security for vibe-coded apps
How to secure a Supabase app: the five settings that matterA Supabase app can be wide open, almost always for the same handful of reasons: RLS off, the service_role key in the browser, public buckets, unguarded functions, secrets in the bundle. Here's the map to closing each one.My API key is showing on my website — is that bad?An API key visible in your frontend is a shrug or an emergency depending on which kind it is. Public keys (anon, pk_, Maps) are meant to be seen; secret keys are compromised the instant they ship. How to tell, and what to do.Is my app built with AI safe? A non-developer's checkYou built an app with AI, it works, and you're quietly worried it's not safe — but you can't read code. Here are the four plain-English questions that matter, and how to check each one without being a developer.Is Lovable secure? The one setting that decides itA Lovable app can be wide open, and the difference is one setting most builders never touch. The anon-key/RLS model, the gap behind a 2025 CVE, and how to check yours.Is Bolt.new secure? What the generated app leaves openBolt.new builds a working full-stack app fast — which is why the security gets skipped. The usual gaps: a Supabase database with RLS off, secrets in the bundle, UI-only authorization. Here's how to audit yours.Is v0 secure? Keeping a generated Next.js app's secrets inv0's Next.js output looks production-ready, which is the trap. NEXT_PUBLIC_ bakes a var into the bundle, and a secret in a client component ships to the browser. Here's how to check a v0 app keeps its secrets in.Vibe coding security risks: the checklist nobody runsThe appeal of vibe coding is that you don't read every line — which is exactly why the holes get through. Exposed secrets, a database anyone can read, rules enforced only in the UI, and how to close each one.

spot something wrong or out of date? [email protected] — we'll fix it

Tell Me When Down

Uptime and security monitoring for people who'd rather ship than babysit servers. We watch so you can sleep.

product
How it worksWhat we checkPricingDocsBlogFAQ
free toolsWebsite security scanSupabase pause checkRender sleep checkMixed content checkerSecurity headers checkCookie security checkSSL expiry check
comparevs UptimeRobotvs Better Stackvs PingdomFor indie hackers
company
StatusAbout our botSupportPrivacyTerms
© 2026 TellMeWhenDown · tellmewhendown.com