In early February 2026, Wiz Research published a write-up on Moltbook, a social network for AI agents whose code was largely AI-generated. The app's Supabase database had tables without Row Level Security, and the data inside was readable and writable by anyone who knew where to look. This post covers what was exposed, what Supabase's own documentation says about the defaults involved, and how to check your own project in an afternoon.
What was exposed
Wiz found 1.5 million API authentication tokens and 35,000 email addresses, along with private messages, readable without login (Wiz Research, 2026). The database held about 17,000 human account owners (Wiz Research, 2026). Wiz reported the issue to the maintainer on 2026-01-31 and a first fix was in place within about two hours (Wiz Research, 2026).
The mechanism matters more than the figures. Supabase's publishable key (formerly called the anon key) sits in the app's JavaScript by design; anyone can read it. It is safe there only because Row Level Security, or RLS, the per-row access rules Postgres applies to each query, decides which rows that key can reach. On Moltbook, tables had no RLS policies, so the public key reached everything. An API token (a long random string an agent presents to prove who it is) in a readable table is as good as a password.
What to check first: sign out of your app completely and follow Row Level Security disabled on a table. If any table shows as Unrestricted, that is your first fix.
What Supabase's docs say about the defaults
Supabase's documentation, as we read it on 2026-09-21, states that the Table Editor enables row level security when you create a table in the Dashboard. When you create a table with SQL, you must enable it yourself. On existing projects, a new table in the public schema starts with every privilege granted to all three roles. A table in an exposed schema without RLS is readable and writable by any role with a grant on it.
That second path is the one AI builders and coding agents use. They create tables through SQL migrations, not by clicking in the dashboard, so the dashboard default does not apply. Nothing has gone wrong at that point; it is a table waiting for a policy.
Supabase's own security features deserve a fair statement here. Its 2025 security retrospective says dashboard-created tables get RLS by default, that Security Advisors flag tables without RLS, and that project owners receive email alerts about them (Supabase, 2026). The Security Advisor runs automatically in Studio and raises an ERROR-level finding named rls_disabled_in_public, plus a warning for policies that allow everything with USING (true). The docs also note the advisor's limit: it checks schema configuration and policies, and application logic is outside its scope.
So the tooling exists. The step that is easy to skip is reading it.
How to check your own project
You do not need to write code for any of this.
- Table Editor. In the Supabase dashboard, open Table Editor and scan the table list for an
RLS disabledorUnrestrictedlabel. Full steps and the bad result: Row Level Security disabled on a table. - Security Advisor. Open Advisors, then Security Advisor, and read every ERROR and WARN line. A
Permissive RLS Policyfinding means a table has RLS on paper but a policy that lets everyone through. Full steps: RLS policy that allows everything with using (true). - What is in the tables. For each table that holds tokens, keys or session identifiers, ask whether the browser needs to read it at all. Tokens for third-party services belong in edge function secrets, not in a table the publishable key can query. Related check: Third-party API key in the JavaScript bundle.
- Rotate what was reachable. If a table with tokens or keys was ever unrestricted, treat every value in it as read. Rotating takes an hour; guessing whether anyone looked takes forever.
Where testing comes in
Supabase did its job: it labelled the tables, ran the advisor and offered the email alert. Testing is a separate job. When we test a Supabase-backed app, we enumerate every table the API exposes using the publishable key, then again as two ordinary signed-in users. We record which rows each role can read, insert, update and delete. The report lists each table with a redacted sample of what came back. That is the check in our security package, and the Supabase hub lists every pattern we test for on this stack.
What to do this week
- Check every table for the Unrestricted label: Row Level Security disabled on a table.
- Read the Security Advisor output and clear each policy warning: RLS policy that allows everything.
- Take the self-check to see which other Supabase checks apply to your app.