Breakdown: how Moltbook's open Supabase database exposed 1.5M agent API keys
By Pritesh Ghodge, security engineer · Published 8 November 2026
Can anyone read (or edit) your Supabase tables?
The Abbi Labs quick check tests your live app as an anonymous visitor: Supabase tables readable with your public key, secret keys in your JavaScript, exposed .env and .git files. No sign-up.
No sign-up. Read-only public-resource and protocol metadata checks. No model prompts or tool execution. Scan only sites you own or are allowed to test.
Run on every deploy or use from Cursor / Claude Code via MCP →
Weekly AI-app security checklist
One short email a week: a practical check for apps built with Supabase, Next.js and AI tools (RLS, leaked keys, headers and more). Unsubscribe anytime.
Moltbook is a Reddit-style social network for AI agents that went viral in late January 2026. Its founder said publicly that he didn't write a line of code for it: the platform was vibe-coded. Within days, two separate researchers found its Supabase database was open to anyone holding the public key from the site's JavaScript. Wiz Research reported that the exposure included about 1.5 million agent API tokens, 35,000 email addresses and private messages between agents, and that unauthenticated visitors could also edit live posts. Moltbook fixed it within hours of Wiz's report. This is a plain-English breakdown of what was reported, why it happened, and how to check your own app.
Timeline
- Late January 2026: Moltbook launches and goes viral as the "front page of the agent internet".
- 31 January 2026: 404 Media reports that security researcher Jameson O'Reilly found an open Moltbook database exposing every agent's API key, claim token and verification code. 404 Media verified the takeover by changing O'Reilly's own Moltbook account, with his permission.
- 31 Jan 21:48 UTC – 1 Feb 01:00 UTC: Wiz (Gal Nagli) independently finds the issue, contacts the maintainer on X, and works through four rounds of fixes: sensitive tables, then messages and notifications, then write access, then more tables found via GraphQL.
- 2 February 2026: Wiz publishes the full scope. TechRadar, Infosecurity Magazine, Gizmodo and others cover it.
What the researchers found
Wiz says it "simply" browsed the site like a normal user and looked at the JavaScript bundles. In a production Next.js chunk it found the Supabase project URL and the sb_publishable_ key. That alone isn't a bug: the publishable key is designed to be public. The problem was what the key could reach.
- Agent credentials: the
agentstable returned each agent'sapi_key,claim_tokenandverification_code. Wiz says that meant every account on the platform could be impersonated with a single API call, including high-karma accounts. - Emails: the
ownerstable held 17,000+ owners' emails (alongside public X handles). A separateobserverstable, found via GraphQL, held 29,631 more emails from early-access signups. - Private messages:
agent_messagesexposed 4,060 DM conversations. Some contained third-party credentials, including plaintext OpenAI API keys. - Write access: Wiz confirmed it could
PATCHexisting posts without logging in. Even after the first fix blocked reads on sensitive tables, writes to public tables were still open. - Scale: using PostgREST error hints and GraphQL introspection, Wiz mapped the schema and estimated about 4.75 million records exposed.
- Metrics: the 1.5 million "agents" belonged to about 17,000 human owners (roughly 88 per person). Wiz notes there was no rate limit on registering agents.
Wiz says all data accessed during the research and fix verification was deleted. Reporting does not establish that anyone else misused the exposure.
Root cause
The same miss as CVE-2025-48757 and the Crissy Field Lovable study, but in one very public app: Row Level Security was missing. Without RLS policies, the public key grants the anon role whatever table privileges it has. On many projects that's every table in public.
Three things made it worse than a read-only leak:
- Secrets lived in normal tables. Agent API keys were stored as plain values in a table the browser could query. Once the table was readable, every account was takeover-able.
- Writes were open too. No
updatepolicy meant anyone could change posts that thousands of AI agents then read. Wiz and O'Reilly both point at prompt-injection risk here. - The schema was discoverable. PostgREST error hints and the GraphQL endpoint let researchers find tables the UI never used, so "nobody knows that table exists" was no protection.
Wiz also notes that each fix round surfaced another exposed surface. Locking down the tables you know about isn't the same as locking down the project.
How to check your own app
Only test projects you own.
- Open your live site, then DevTools → Sources (or Network). Search your JS bundles for
supabase.coandsb_publishable_/eyJ. That's what anyone can see. - Try reading a table with only that key:
curl "https://YOUR-PROJECT.supabase.co/rest/v1/TABLE?select=*&limit=1" \
-H "apikey: YOUR_PUBLISHABLE_KEY" \
-H "Authorization: Bearer YOUR_PUBLISHABLE_KEY"[]or a permission error: an anonymous visitor gets nothing. Good.- A row of real data: anyone on the internet can read that table.
- Find every table that has no RLS at all, not just the ones your UI calls:
select c.relname as table_name, c.relrowsecurity as rls_on
from pg_class c join pg_namespace n on n.oid = c.relnamespace
where n.nspname = 'public' and c.relkind = 'r'
order by rls_on, table_name;- List policies and look at writes, not just reads:
select tablename, policyname, roles, cmd, qual, with_check
from pg_policies
where schemaname = 'public'
order by tablename, cmd;An update, insert or delete policy with true for anon or public means anyone can change your data. Also open Database → Security Advisor and clear the "RLS disabled" warnings.
- Search for secrets stored as plain columns: anything named
api_key,token,secret,claim_tokenorpassword.
select table_name, column_name
from information_schema.columns
where table_schema = 'public'
and column_name ~* '(api_?key|token|secret|password)';The free Supabase RLS policy checker reads pg_policies for you in your browser.
Rather not curl every table by hand?
Paste your URL and Abbi Labs runs the anonymous checks for you (one row max per table, read-only, nothing stored).
Fix steps
- Turn on RLS for every table in
public, including ones the UI doesn't use:
alter table public.agents enable row level security;
alter table public.agent_messages enable row level security;- Write owner-only policies for reads and writes:
create policy "owner reads"
on public.posts for select
to authenticated
using ((select auth.uid()) = owner_id);
create policy "owner edits"
on public.posts for update
to authenticated
using ((select auth.uid()) = owner_id)
with check ((select auth.uid()) = owner_id);If posts are meant to be public, a public select policy is fine. Just never pair it with an open update.
- Keep secrets out of browser-reachable tables. Store API keys hashed (compare a hash on the server), or in a schema the
anonandauthenticatedroles can't see. Revoke what the browser doesn't need:
revoke all on table public.agents from anon;- Rotate anything that was exposed. If keys or tokens sat in an open table, assume they're copied and issue new ones.
- Shrink what's discoverable. If you don't use Supabase GraphQL, consider disabling the
pg_graphqlextension. Either way, RLS has to hold on every table, because hidden tables get found. - Add rate limits on sign-up and resource creation so one script can't create a million accounts.
- Re-test signed out after every fix round, reads and writes. Moltbook needed four rounds.
The takeaway
Moltbook is the clearest single example yet of the pattern behind CVE-2025-48757: the publishable key in your JavaScript isn't the bug, missing RLS is. What it adds is how bad it gets when the open tables hold credentials and the write side is open too. Shipping fast with AI is fine. Just spend ten minutes testing your app from the outside, as an anonymous visitor, before real users show up.
Abbi Labs runs these anonymous checks for you (one row max per table, nothing stored), and the free Supabase RLS policy checker reads your policies. Or use the curl and SQL checks above.
Sources
- Wiz Research (Gal Nagli), "Hacking Moltbook: The AI Social Network Any Human Can Control", 2 Feb 2026 (primary; includes disclosure timeline)
- 404 Media, Exposed Moltbook Database Let Anyone Take Control of Any AI Agent on the Site, 31 Jan 2026
- TechRadar, Moltbook is a security disaster, 3 Feb 2026
- Gizmodo, It Turns Out 'Social Media for AI Agents' Is a Security Nightmare
- Infosecurity Magazine, Vibe-Coded Moltbook Exposes User Data, API Keys and More
Related
- Breakdown: Crissy Field found thousands of Lovable apps with open Supabase tables
- Breakdown: how 170 Lovable apps left their Supabase data open (CVE-2025-48757)
- How to check if your Supabase tables are readable by anyone
- Is the Supabase anon key safe to expose?
- Supabase WITH CHECK (true): what that INSERT policy actually opens