
🤖 Ghostwritten by Claude Opus 4.6 · Fact-checked & edited by GPT 5.4 · Curated by Tom Hundley
If you built a Supabase app with AI assistance, the first thing to verify is simple: is Row Level Security enabled on every table your client can reach? If not, users may be able to read or modify data they should never see. That risk does not come from your public anon key alone. It comes from combining a public client key with missing or overly broad database policies.
A recent wave of exposed Supabase projects has made that failure mode hard to ignore. The lesson is straightforward: AI coding tools can scaffold auth, tables, and CRUD flows quickly, but they do not reliably design secure access policies unless you ask for them explicitly. If you are shipping fast with Supabase, you need to treat RLS review as part of the build, not a cleanup task for later.
This article explains the underlying risk, clarifies what RLS actually does, and gives you a practical checklist to audit your project today. If you are new to secure AI-assisted development, our guides on shipping AI prototypes responsibly and common security gaps in rapid app builds provide useful companion reading.
TL;DR: The common failure pattern is not a hidden exploit. It is a public client key combined with missing RLS policies on tables exposed through the API.
Several public reports and security writeups have highlighted the same pattern: developers ship a Supabase-backed app, include the public anon key in frontend code as intended, but fail to enable or correctly configure Row Level Security on the underlying tables.
That combination is dangerous because:
The important point is that this is usually not a sophisticated breach. In many cases, an attacker only needs the same information any browser user already has: the app's public key and API endpoint. From there, the real control boundary is the database policy layer.
If your team is using AI tools to generate Supabase code, review the generated SQL and auth flows the same way you would review hand-written code. Our post on how to review AI-generated application code covers a practical review process.
TL;DR: AI tools are good at scaffolding features, but they often omit security controls that were never specified in the prompt.
When you ask an AI assistant to build a Supabase app, it will often generate:
What it may not generate unless you ask:
ALTER TABLE ... ENABLE ROW LEVEL SECURITYCREATE POLICY statements| Common AI-generated output | Common omission |
|---|---|
| Table creation SQL | RLS enablement |
| Frontend Supabase client setup | Least-privilege access design |
| Sign-up and sign-in flows | Per-operation policies |
| CRUD examples | Negative tests for unauthorized access |
This is not unique to one model or coding tool. It is a predictable result of prompt-driven generation. If the prompt says "build the feature," the model may optimize for a working feature, not a hardened one.
That is why secure prompting matters. Ask for policies, threat assumptions, and tests explicitly. Better yet, require the model to explain why each policy exists.
TL;DR: RLS is a PostgreSQL feature that restricts which rows a role can access, and Supabase relies on it to safely expose data to client applications.
Row Level Security is a native PostgreSQL capability. When enabled on a table, it allows access decisions to be evaluated per row based on policies you define. In Supabase, this is a core part of safely exposing database-backed APIs to browser and mobile clients.
A simple mental model:
For example:
ALTER TABLE messages ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users can read own messages"
ON messages
FOR SELECT
USING (auth.uid() = user_id);
CREATE POLICY "Users can insert own messages"
ON messages
FOR INSERT
WITH CHECK (auth.uid() = user_id);That pattern is common, but do not copy it blindly. The exact policy depends on your schema, ownership model, and whether admins, teams, or background jobs also need access.
One nuance matters here: enabling RLS is necessary, but not sufficient. A table with RLS enabled can still be exposed if you add a policy that is too broad, such as allowing all authenticated users to read every row. The goal is not just "RLS on." The goal is correct, least-privilege policies.
TL;DR: Audit every exposed table, enable RLS where needed, review policies for least privilege, and keep privileged keys strictly server-side.
In the Supabase dashboard, inspect each table your application uses. If a table is reachable from client code, verify whether RLS is enabled and whether the policies are appropriately scoped.
You can also inspect table settings from SQL:
SELECT tablename, rowsecurity
FROM pg_tables
WHERE schemaname = 'public';Treat any table with rowsecurity = false as a review item. Whether it is truly exposed depends on how the API is configured and which roles can access it, but for client-facing Supabase apps, disabled RLS on application tables is usually a red flag.
ALTER TABLE your_table ENABLE ROW LEVEL SECURITY;In PostgreSQL and Supabase, enabling RLS without adding permissive policies generally results in denied access for roles subject to RLS. That fail-closed behavior is usually safer than leaving a table open, but test carefully before changing production behavior.
Review who should be allowed to:
SELECTINSERTUPDATEDELETEThen write explicit policies for each operation. In many apps, auth.uid() is part of the condition, but team-based access, admin roles, and system workflows often require more than a single user-to-row match.
Supabase uses a public client key for browser and mobile access. Privileged keys, including service-role credentials, must stay on trusted server infrastructure because they can bypass normal client restrictions.
Use environment variables and server-side handlers for privileged operations:
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_ROLE_KEY=YOUR_SERVICE_ROLE_KEYNever embed privileged credentials in frontend bundles, mobile apps, or public repositories.
Use prompts like:
"Enable Row Level Security on all client-accessible tables. Generate least-privilege policies for SELECT, INSERT, UPDATE, and DELETE, and explain the reasoning for each policy."
"Review my Supabase architecture for places where privileged keys are used. Move privileged operations to server-side code and list any remaining risks."
"Generate tests that confirm one authenticated user cannot read or modify another user's rows."
The key habit is simple: do not ask only for working code. Ask for secure code, policy rationale, and abuse-case tests.
TL;DR: The short answers are yes, RLS is essential; no, public client keys are not the main problem; and yes, policy mistakes can still break a production app even after RLS is enabled.
Yes, the public client key is intended to be used in frontend applications. The security boundary is not secrecy of that key. The real protection comes from RLS, auth, and careful policy design.
For roles subject to RLS, access is typically denied by default. That is safer than accidental overexposure, but it can break application behavior immediately if you have not added the policies your app needs.
Usually yes, but you should treat it as a potentially breaking access-control change. Test in staging first, verify all expected queries, and roll out with monitoring so you can catch blocked application paths quickly.
Review database and API logs for unusual read patterns, broad table access, or requests inconsistent with normal user behavior. If sensitive data may have been exposed, involve security and legal stakeholders early so you can assess notification obligations.
Supabase surfaces RLS status in the dashboard and strongly recommends using it for exposed tables. Those signals help, but they are not a substitute for a deployment checklist or code review.
Fast iteration is useful. Blind trust in generated defaults is not. If you are building with Supabase and AI assistance, make RLS review part of your definition of done.
If you want a second set of eyes before launch, Elegant Software Solutions helps teams review AI-generated applications, database policies, and deployment security controls. We can help you identify exposed tables, overly broad policies, and risky key handling before they become incident-response work.
Discover more content: