How to tell if your Supabase database is exposed (without being a developer)
By Seth Tucker · Updated June 2026
Log in to your Supabase dashboard, open the Table Editor, click on any table that holds user data, and look for a shield icon or "RLS enabled" label. If that label is missing or shows as disabled, your database is exposed to anyone who has your project's public key — which is almost certainly embedded in your app's frontend code. That is the single most important thing to check, and you can do it right now.
Why Supabase is worth its own article
Supabase is the most common database behind vibe-coded apps. Lovable, Replit, Bolt, v0, and Claude Code-generated apps frequently default to Supabase for their backend. It is a well-designed tool. It is also a tool that ships with a public API key in your frontend code by design — and that is completely fine, as long as you understand what that key can do and have configured the rules that limit it.
When that configuration is not in place, the database is reachable by anyone with the key. The key is in your frontend. Your frontend is publicly accessible. The math on that is straightforward.
Security researchers at RedAccess found more than 5,000 vibe-coded apps with little or no authentication or security controls — approximately 40 percent exposed sensitive data. Supabase misconfiguration is one of the most commonly flagged patterns in the accompanying community discussions.
This article translates the relevant concepts — RLS, the anon key, the service-role key, table policies — into plain language, then gives you a step-by-step check you can run without writing a single line of code.
The three concepts to understand
You do not need to understand SQL or backend infrastructure. You do need to understand these three things before you can evaluate whether your Supabase database is safe.
The anon key: the key that is in your frontend
When you connect your app to Supabase, the AI builder puts a credential called the anon key (also called the public key) in your frontend code. This is intentional. Supabase expects this key to be public — it is how your app's frontend communicates with the database without requiring a separate authentication layer for every single request.
The anon key is not a secret. It is meant to be visible.
The catch: by default, that anon key can read and write everything in your database. Every table. Every row. Every user's data. "By default" means: before you configure Row Level Security.
The service-role key: the key that must never be in your frontend
Your Supabase project also has a service-role key (sometimes called the secret key). This key bypasses all security rules. If you have the service-role key, you have full admin access to the database — read, write, delete, anything, for any user, with no restrictions.
This key must never appear in your frontend code. It should only be used in server-side code that runs on a machine you control, not in the browser. If you find this key in your app's frontend, treat it as a critical failure: rotate it immediately from the Supabase dashboard and remove it from any frontend code before you do anything else.
Supabase's own documentation explicitly warns that the service-role key can bypass RLS and must be handled carefully.
Row Level Security: the rules that make the anon key safe
Row Level Security (RLS) is Supabase's access control system. It is a set of rules that you define — or that the AI defined when it built your app — that determine which rows of each table a given user is allowed to read or modify.
When RLS is enabled and configured correctly, a request using the anon key can only access the rows that belong to the authenticated user making the request. One user cannot read another user's data. An unauthenticated request returns nothing (or only publicly designated content).
When RLS is disabled on a table, the anon key can access every row in that table. No restrictions.
Supabase's documentation states that RLS must always be enabled on tables in schemas that are exposed via the API, which includes the default public schema.
The guided self-check: five steps without writing code
Work through these steps in order. Each one takes two to five minutes.
Step 1: Find your Supabase dashboard
Go to supabase.com, log in, and open the project associated with your app. If your app was built by an AI builder, the project URL and credentials were generated during the setup process — check your builder's settings panel or environment configuration for the Supabase project URL.
Step 2: Check which keys are in your frontend
In your Supabase dashboard, go to Project Settings then API. You will see two keys: the anon / public key and the service-role key.
Now look at your app's code (in Lovable, Replit, Bolt, or wherever you built it). Search for both of those key strings.
- The anon key being in the frontend code is expected. This is fine.
- The service-role key being in the frontend code is a critical problem. Rotate it immediately from this same settings panel (use the "Reveal" and then "Rotate" options) and remove it from any frontend code.
Step 3: Check Row Level Security on each table
In your Supabase dashboard, go to Table Editor. You will see a list of tables — these are the named collections of data your app uses (for example: users, orders, messages, profiles, notes).
For each table that contains user data or anything you would not want any random person to read:
- Click on the table name.
- Look for an RLS indicator. In the Supabase interface, this appears as a toggle, a shield icon, or a status label near the top of the table view.
- If it shows RLS: Enabled — proceed to Step 4.
- If it shows RLS: Disabled or there is no indicator — this table is exposed. Any request using the anon key can read the entire table. Note this table and continue checking the others.
What to do if RLS is disabled: You need to enable it and add policies. This is a technical step — it requires writing SQL policy statements that tell Supabase who can access which rows. If you are not comfortable with SQL, this is the moment to get a developer involved. The Supabase documentation has a policy editor with templates for common patterns.
Step 4: Check whether any policies exist
RLS being "enabled" is not sufficient on its own. A table can have RLS enabled with no policies defined — and in Supabase, a table with RLS enabled and no policies returns zero rows to all requests. That is technically "secure" (nothing is exposed), but it also means your app will show blank data to logged-in users, which is a different kind of problem.
While looking at each table in the Supabase Table Editor, check whether there are policies defined. If you navigate to the Authentication section of your Supabase dashboard and then to Policies, you will see all policies organized by table.
For each table with user data, there should be at least:
- A policy that allows a logged-in user to read their own rows (typically:
auth.uid() = user_idor similar). - A policy that allows a logged-in user to insert or update their own rows.
If there are no policies, or if you see policies that say true with no condition, get a developer to review the policy logic before inviting users.
Step 5: Verify with a practical test
This is the most direct check, and it requires two test accounts. Create two test user accounts in your app (use fake email addresses if your app allows it, or use email aliases like [email protected] and [email protected]).
- Log in as User A and create a record — a note, a profile entry, an order, whatever your app stores.
- Note the ID or URL associated with that record.
- Log out. Log in as User B.
- Try to navigate to that record's URL, or use the app's interface to find it.
If User B can see User A's record, RLS is either disabled or misconfigured. This is Broken Object Level Authorization — one of the most common failures in AI-built apps, and the one OWASP consistently ranks as the top API vulnerability.
What you are looking for: a quick-reference summary
| Item to check | Safe | Needs attention |
|---|---|---|
| Anon key location | In frontend code — expected and fine | Not applicable |
| Service-role key location | Only in server-side code | In frontend code — rotate immediately |
| RLS status on user-data tables | Enabled | Disabled — table is exposed |
| Policies defined on each RLS-enabled table | At least one read + one write policy per table, with user-identity conditions | No policies, or policies with bare true condition |
| User B can access User A's records | No — returns nothing or an error | Yes — data isolation is broken |
| Unauthenticated request to a data endpoint returns user data | No — returns nothing or an auth error | Yes — server-side auth is missing |
What RLS does not protect against
RLS is one layer. Knowing what it does not do is as important as knowing what it does.
RLS does not protect against a misconfigured policy. A policy that says true with no condition gives everyone access to every row. A policy that uses the wrong column name for the user comparison does the same. The policy needs to be correct, not just present.
RLS does not protect the service-role key. Any code — including your own backend — that uses the service-role key bypasses RLS entirely. That key must be protected as carefully as a password.
RLS does not replace server-side authentication checks. If your app has an endpoint that returns data, the endpoint should verify the user's identity before calling the database — not rely on RLS as the only guard. Defense in depth means both layers.
RLS does not protect non-Supabase parts of your app. If your app uses external APIs, file storage, payment services, or email — those have their own access controls and are not covered by Supabase RLS.
Tool-specific notes
Lovable apps using Supabase
Lovable generates Supabase integration code, including RLS policies, as part of the build process. The quality of those policies depends on how clearly the app's data model and user permissions were specified. If you did not explicitly specify "User A cannot see User B's data" in your prompts — and most people do not — the AI may have generated a functional data model without the access control policies to match.
The most common pattern: Lovable creates tables and connects them to the frontend correctly, but either omits RLS entirely or creates permissive policies that pass the happy path (your own data) without enforcing isolation (other users' data).
Replit apps using Supabase
Replit users frequently connect to Supabase for a persistent backend. Replit's server-side code can use the service-role key safely — but only if that key is stored in the Replit Secrets manager and not in the code itself. If the AI-generated Replit code references the service-role key in a file that is committed to a repository or exposed in a public app, rotate it immediately.
v0 and Bolt apps using Supabase
Both tools generate primarily frontend code. Any Supabase integration in a v0 or Bolt app is communicating through the frontend — meaning only the anon key, and only operations permitted by RLS policies. Check that RLS is enabled on all tables your frontend queries. The frontend-only architecture also means server-side authorization checks cannot exist — everything depends on RLS being correct.
Claude Code or Cursor apps using Supabase
These tools generate a complete codebase, which can include server-side code with service-role key usage. Review any generated code that references the service-role key — confirm it is only in server-side files, that those files are not exposed publicly, and that .env or equivalent config is excluded from version control.
When to get a developer involved
You do not need a developer to run the checks in this guide. You do need a developer — or a security-focused technical reviewer — for:
- Writing or correcting RLS policies.
- Verifying that server-side authentication middleware is present and correctly applied.
- Reviewing generated policy logic for edge cases (admin users, shared resources, team access).
- Confirming that the service-role key's usage in server-side code is appropriate and necessary.
- Auditing the full data access path from frontend request through to database query.
If you would like AgentC to walk through the Supabase configuration for your specific app — with a developer's eye on the policy logic and the data access patterns — the right starting point is a demo conversation.
Related guides in this series
- Is your AI-built app safe to put in front of customers? (the pillar guide) — the full triage across all security areas
- The pre-launch security checklist for Lovable, Replit, Bolt, and Base44 — complete cross-platform checklist
- Production-ready vs demo-good: the vibe-coding reality check
- Can someone see another user's data in your AI-built app?
Frequently asked questions
Is the Supabase anon key a secret?
No. The anon (public) key is designed to be used in frontend code and is therefore visible to anyone who looks at your app's network requests or source code. That is expected. The key's safety depends entirely on Row Level Security being enabled and correctly configured on your tables — without RLS, anyone with the anon key can read your entire database. The service-role key, by contrast, must be kept secret and must never appear in frontend code.
My app is working fine. Does that mean RLS is configured correctly?
Not necessarily. A working app means that your own requests return your own data. It does not mean that another user's requests are restricted. Apps with no RLS policies often work perfectly for the happy path — the user sees their own data because they are the only user you have tested with. The failure appears when a second user can also see the first user's data. Testing with two separate accounts is the only reliable way to verify this.
Can I check RLS without logging in to Supabase?
Not directly — you need Supabase dashboard access to see the RLS settings and policies. If you do not have dashboard access (for example, if someone else set up the project), get the credentials from your AI builder's settings or from whoever configured the project. If you cannot access the Supabase dashboard at all, treat the database's configuration as unknown and get technical help before inviting users.
What if I enabled RLS but did not add any policies?
Supabase returns zero rows for all requests on a table with RLS enabled and no policies. Your app will appear to have no data — logged-in users will see empty lists. This is a different problem from an exposed database, but it is still a broken app. You need to add policies that allow authenticated users to access their own rows. The Supabase documentation has a policy builder with common templates.
Does using Supabase Auth mean my database is protected?
Supabase Auth handles the login and session management — it tells Supabase who the current user is. That user identity is available to RLS policies (as auth.uid()). But Auth alone does not protect your data — it provides the identity that your policies check. If there are no policies, or if the policies do not reference the user identity, Auth does not prevent one user from accessing another's data.
I am not technical enough to write RLS policies. What should I do?
Three options. First, use Supabase's AI assistant in the dashboard to generate policy templates — it can produce basic "users can only access their own rows" patterns from a plain-language description. Second, ask the AI builder (Lovable, Claude in Cursor, etc.) to generate and apply RLS policies for your specific tables and user model. Third, get a developer or a security-focused technical reviewer to write and verify the policies. Do not launch with user data until one of these three paths is complete.
About this guide
Written by Seth Tucker, founder of AgentC Consulting. Seth spent approximately five years as a security engineer on election infrastructure used by roughly one in three American voters, holds SOC 2 Type 2 and ISO 27001 experience, and now helps non-technical founders and operators build, review, and trust AI-built applications.
Last updated: June 2026. Sources cited throughout reference original research, vendor documentation, and public reporting.
More than vibes
Want a second set of eyes on your app?
The right starting point is a demo conversation, not a form. We look at what you built, ask the questions that matter for your situation, and tell you plainly what is safe to ship and what needs work first.