
If you've built an app with Cursor, Bolt, or Lovable and wired it to Supabase, here's a question that decides whether your data is safe or wide open: did you enable Row Level Security?
If you're not sure, this lesson is for you. No jargon, no shame โ just the one mistake that turned a startup's database into a public download, and the three things to do about it today.
In early 2026, security researchers at Wiz found a Supabase database belonging to Moltbook โ a viral "social network for AI agents" โ sitting completely open. Anyone could read and write every row.
The numbers Wiz documented: 1.5 million API authentication tokens, 35,000 user email addresses, and 4,060 private conversations โ some of which contained plaintext OpenAI API keys that agents had shared with each other.
Here's the part that matters for you, because it's the exact stack vibe coders use: the app was built fast, the Supabase key was hardcoded into the front-end JavaScript, and Row Level Security was never turned on. That combination is what blew the doors off.
This is the most important misunderstanding to clear up. Supabase gives you (at least) two keys:
sb_publishable_...). This one is designed to be public. Supabase's own docs say it's safe to ship in a web page, a mobile app, or source code.sb_secret_...). This is a master key. It carries a Postgres power called BYPASSRLS, which means it skips every security rule you set and can read and write all your data. It must never leave your backend.So Moltbook putting the anon key in the browser was not the bug โ that key is supposed to be visible. The bug was that nothing protected the data behind it. That "something" is Row Level Security.
The anon key gets a visitor into the lobby. Row Level Security (RLS) decides which rooms they can enter โ a set of rules, enforced by the database itself, that says "this person can only see their own rows" or "nobody can read this table at all."
Supabase is blunt in its security docs: "Always enable Row Level Security on tables and views you expose." And critically โ any table you create in the SQL editor does NOT have RLS on by default. You turn it on yourself.
When RLS is off, your public anon key becomes a master key by accident. That's exactly what happened to Moltbook: a public key with no rules behind it means anyone on the internet can download everything.
If the secret key leaks โ or you leave RLS off โ the financial blast radius is real, not theoretical. In a separate 2026 incident, a three-person startup had a Google Gemini API key stolen. In 48 hours, attackers ran up $82,314 in charges, mostly generating AI content on the company's dime. Their normal bill was about $180 a month. As The Register reported, Google declined to forgive the charges, citing shared responsibility.
A related trap: cloud keys are often "unrestricted" by default, so a key you made for one purpose can silently gain access to expensive new services the moment you enable them. Lock cloud keys down to the one service they need.
1. Rotate the key first. If a secret/service_role key has ever been pasted into client code, a public repo, or a chat prompt โ assume it's compromised and rotate it immediately. Rotating (revoking the old key and issuing a new one) is the only action that actually stops someone from using a stolen key. Cleaning it out of your code afterward is housekeeping; rotation is the fix. The new secret keys (sb_secret_...) can be revoked instantly from the Supabase dashboard.
2. Enable RLS on every table. Open your Supabase dashboard, go to each table, and turn on Row Level Security โ then add a policy that grants access only to the rows a user should see. A table with RLS enabled but no policy denies everyone by default, which is a safe starting point. No table you expose should be without it.
3. Keep the service_role/secret key server-side only. It belongs in backend code, edge functions, or environment variables your users never see โ never in front-end JavaScript, never in a public repo, and never pasted into an AI chat window. Your .env file holds it; .gitignore keeps .env out of git.
You don't have to do this by hand. Paste this into Cursor, Bolt, or Lovable:
Audit this project for Supabase security problems. Specifically:
1. Find any Supabase service_role or secret key (sb_secret_...) used
in client-side / front-end code, and flag it as critical.
2. List every Supabase table my app uses, and tell me which ones do
NOT have Row Level Security enabled.
3. Check that my .env file is listed in .gitignore and that no keys
are hardcoded in committed source files.
Report each issue with the file and line number, and suggest a fix.
Do not print the actual key values โ just say where they are.That last line matters: you never want your own keys echoed back into a chat log.
Is the Supabase anon key actually safe to expose?
Yes โ on its own. Supabase designed the anon (publishable) key to be public and ship in browser code. It is only dangerous when you've left Row Level Security off, because then it can reach data it was never meant to. Safe key + RLS on = fine. Safe key + RLS off = open database.
What's the difference between the anon key and the service_role key?
The anon/publishable key is low-privilege and obeys your RLS rules โ it's for the browser. The service_role/secret key carries BYPASSRLS, ignores every rule, and has full read/write access โ it's for your backend only and should never be exposed.
I deleted the leaked key from my code. Am I safe now?
No. Deleting a key does nothing to a copy someone already grabbed โ and if it was ever committed, it's still in your git history. You must rotate it (revoke the old one, generate a new one) in the Supabase dashboard. That's the only step that makes the old key useless.
What are these new "publishable" and "secret" keys I'm seeing?
Supabase is moving from the old anon/service_role keys to sb_publishable_... and sb_secret_... keys. They work the same way conceptually โ publishable is the public, RLS-respecting one; secret is the powerful backend-only one โ but the new secret keys can be rotated and revoked instantly, which makes cleaning up after a leak far easier. If your project offers them, use them.
Why shouldn't I paste an API key into an AI chat?
Because that chat is a log, and that log is one more place your secret now lives. If your AI assistant needs to check your keys, ask it to report where they are by file and line โ not to print the values.
Discover more content: