// ANSWER

How do I know if my Supabase database is exposed?

Updated 2026-08-07 · 7 min read

The short answer

Seeing your Supabase URL and "anon" key in the browser does not mean your database is exposed, those are designed to be public. What decides whether strangers can read or change your data is Row Level Security (RLS): a per-table gate that must be turned on with policies that actually restrict access. If a table has RLS off, or a policy that always passes, anyone who opens your app can pull every row through Supabase's automatic API. The fastest check is your Supabase dashboard, and you can confirm it in your browser's network tab in about a minute.

First: the anon key in your browser is supposed to be there

When you built your app, your AI tool put a Supabase URL and a long "anon" (anonymous / publishable) key into the front-end code. Anyone can see it, right-click, View Source, and there it is. This scares a lot of founders, but it is by design. That key only identifies your project; it is not a password. Supabase expects it to live in the browser.

The thing that actually protects your data is a separate layer called Row Level Security. So the anon key being visible is not the problem. A missing or fake RLS policy is. There is a second, different key, the "service_role" key, that does bypass all protection. That one must never appear in your browser or your public code.

Anon key in the browser = normal. service_role key in the browser = emergency, rotate it immediately and move it to server-side code only.

The real test is Row Level Security (RLS)

Supabase automatically exposes every table in your database through a web API. That means a table called "profiles" or "orders" can be requested directly over the internet, using only the public anon key, unless something stops it. Row Level Security is that something.

RLS works in two steps, and you need both. First, RLS has to be turned ON for the table. Second, you write policies that say who can see or change which rows, for example, "a user can only read their own row." If RLS is off, the table is wide open. If RLS is on but the only policy always says yes, it is also wide open. "Exposed" almost always means one of those two.

How to check a table's policies in the dashboard

You do not need to write code to check this. In your Supabase project dashboard:

  1. Open the Table Editor and look at your list of tables. Supabase flags tables without protection, a table showing an "Unrestricted" label (or a warning icon) has RLS off and is readable by anyone.
  2. Go to Authentication → Policies (or Database → Policies). For each table, read the policies listed.
  3. A protected table has RLS enabled and at least one policy that references the logged-in user, you will see something like auth.uid() = user_id.
  4. A table with RLS enabled but zero policies blocks everyone (safe, though your app may break). A table with RLS off, or a policy set to "true", lets everyone in.

Check every table that holds anything private: users, profiles, orders, messages, uploads, API keys, subscriptions.

What "using (true)" actually means

When you read a policy, the part after "using" is the condition Supabase checks before it hands over a row. If that condition is the word true, it passes for everyone, every time, which is the same as having no protection at all. AI tools sometimes generate this to make the app "just work" during building, and it quietly ships to production.

Here is the difference in plain SQL. The first policy lets the whole internet read the table. The second only lets people read their own rows.

Wide-open vs. locked-down (orders table)
-- EXPOSED: this passes for anyone with your public anon key
create policy "read orders"
  on orders for select
  using ( true );

-- SAFE: a signed-in user can only read rows that belong to them
create policy "read own orders"
  on orders for select
  using ( auth.uid() = user_id );

The network-tab tell (a 60-second test anyone can do)

You can watch your own app talk to Supabase. Open your live site, press F12 (or right-click → Inspect) to open developer tools, and click the "Network" tab. Reload the page and use the app for a moment.

  • Look for requests going to a URL like your-project.supabase.co/rest/v1/something, that "something" is a table name.
  • Click one and look at the response. If you can see rows of real data before logging in, or data that belongs to other users, that table is exposed.
  • A telling sign: paste that same /rest/v1/ request URL into a fresh private browser window with no login. If it still returns data, so can a stranger.

This shows you the same thing an opportunistic scanner sees. If a table hands over data to a logged-out request, treat it as public.

What "exposed" looks like vs. what is fine

To keep it straight: your anon key being visible is fine. Your Supabase URL being visible is fine. A public table that only contains genuinely public content (like blog posts you want everyone to read) is fine. What is not fine is any table with private data that returns rows to a logged-out or unrelated request. If you are unsure, a scan can check every table for you in about a minute and tell you which ones are open, without touching or storing your data.

Key takeaways

  • Your Supabase anon key is meant to be public, its visibility is not the vulnerability.
  • Row Level Security is the real gate: it must be turned on AND backed by policies that restrict rows.
  • A policy that uses "true" allows everyone, it is the same as no protection.
  • The service_role key must never appear in your browser or public code; rotate it if it has.
  • You can confirm exposure yourself in the network tab: if a logged-out request returns private rows, that table is open.

Frequently asked

Is it dangerous that my Supabase key is visible in the browser?

Not on its own. The anon (publishable) key is designed to be public and only identifies your project. Your protection comes from Row Level Security, not from hiding that key. The key you must keep secret is the service_role key.

Does turning on RLS break my app?

It can, temporarily. Enabling RLS with no policies blocks all access, so parts of your app may stop loading until you add policies that allow the right people to see the right rows. That is expected, it means the gate is now closed and you are deciding who gets through.

I never touched security settings, am I protected by default?

Do not assume so. Whether a given table ends up protected depends on how your AI tool generated it and whether policies were added. The only way to be sure is to check each table's RLS status and policies, or run a scan that does it for you.

Can someone really find my database without knowing my company?

Yes. Attackers rarely target a specific small app, automated tools scan public code and live endpoints for open databases at scale. Your app does not need to be famous to be found.

Run a free security scan

Paste your app's link and get a plain-English A–F grade in about 60 seconds, plus the exact fix for every issue.

Free · No signup · Your code stays yours · Results in ~60s