Anatomy of the Moltbook hack — 1.5 million API keys in 72 hours
Moltbook leaked 1.5 million API keys, 35,000 emails, and 4,060 private messages in 72 hours. Wiz's disclosure showed the root cause: a single Supabase table without row-level security. Here is the timeline, the exact bug, and the ten-minute hardening walkthrough for your own app.
Wiz disclosed the Moltbook breach on January 28, 2026. 1.5 million API keys, 35,000 email addresses, and 4,060 private messages reachable via an unauthenticated HTTP request. In this post I will walk through the exact bug Wiz described, reproduce the bypass at a code level, and give you the ten-minute Supabase hardening drill we run internally.
The one-line bug
Moltbook shipped a Supabase table named roughly agent_credentials with RLS disabled. That single change is enough to make every row reachable by anyone who knows the project URL and the public anon key — both of which ship in the client bundle by design.
Why it shipped
Two compounding mistakes:
1. RLS was never enabled on that table. In new Supabase projects, RLS is opt-in per table — you must explicitly run enable row level security on each one. An AI coding assistant will not reliably prompt you to do this.
2. The table stored cross-agent shared credentials. Even with RLS, a policy like USING (auth.uid() = owner) only scopes by user. If the application was designed to let agents share credentials via a shared field, the scoping was never strict enough.
Ten-minute Supabase hardening drill
Run these four steps, in order, right now on your own app:
Step 1 — Enable RLS on every table.
select 'alter table ' || quote_ident(schemaname) || '.' || quote_ident(tablename)
|| ' enable row level security;' as command
from pg_tables
where schemaname = 'public'
and not rowsecurity;That returns the exact alter table commands to run for every table missing RLS.
Step 2 — Add a default-deny policy to every enabled table.
create policy deny_all on public.<table>
for all using (false) with check (false);Then layer explicit allow policies on top. Default-deny is the single biggest leap in Supabase security posture; almost no AI-assisted app does this.
Step 3 — Scope by both user and tenant in every policy.
create policy users_read_own_tenant
on public.orders for select
using (auth.uid() = user_id
and tenant_id = (auth.jwt() ->> 'tenant')::uuid);Step 4 — Rotate anything that looks like a service-role key. If your git history has ever contained a string starting with eyJhbG in a .env file, rotate it now. Run trufflehog git file://. or gitleaks detect locally to check, or request Securie access for an automated sweep when your repo is enabled.
What Moltbook did not have that would have helped
A pre-deploy gate running on every commit. The agent_credentials table existed in the migration history — any automated scanner that understood RLS would have flagged it before it shipped. That is exactly what Securie turns into a Securie review: request repo review and the RLS specialist runs on every pull request after install.
Related reading
- Securie Supabase RLS review — run the RLS specialist inside one Securie review
- Wiz's original technical write-up: wiz.io/blog/exposed-moltbook-database-reveals-millions-of-api-keys
Related posts
From a growing sample of publicly-reachable Supabase projects we've audited, the same seven mistakes come up every time: RLS off on at least one table, service-role key in the client, missing tenant scoping, default-allow policies, no policies on storage buckets, exposed JWT secret, and over-broad anon-role grants. Fixes for each.
It's 3 AM. You scrolled X and saw a tweet about a Lovable / Bolt / v0 app leaking customer data. You start wondering if yours is next. Here is the exact checklist to run in the next 30 minutes — what to check, what to fix first, and how to stop having this problem.
We ran 500 authentication-related prompts against Claude Opus 4.7, GPT-5.4, Gemini 2.5, and DeepSeek V3.2. 92% of the generated code had at least one security bug. Here is the catalog of the top seven recurring mistakes.
The Next.js middleware-bypass vulnerability was disclosed in March 2025 and patched within 24 hours. One year later, forty percent of public Next.js apps are still running vulnerable versions. Here is why, and the two-minute check to run on yours.