What it is and why it matters
The video's title comes from the news. According to an analysis reported by Axios (May 2026), of about 380,000 apps published with AI tools, about 5,000 exposed sensitive data. And TechCrunch (September 2026): the company UpGuard found about 16,000 databases on Supabase with accessible personal data. When I read news like that, there's only one question I care about: is mine one of them? You can't tell by using the app, because when you're logged in your data shows up the way it should. You only find out by testing.
The mechanism, in short. Many apps built with AI talk directly to the database, like Supabase, from the browser or the phone. To do that they carry the project's address and a public key, which anyone can see. That's fine: what protects the data isn't the key, it's the rules on the database. On Supabase they're called Row Level Security. If they're missing, that key opens the tables to everyone.
I've already covered this in the PORTA guide (strikt.fit/porta), with the details on Supabase, Firebase and the two keys. Here is the version to do right now: two one-minute checks, the prompt that closes things and tests again, and how to read the before and after.
Only on your own app
You run this test on your own app and your own database, with test accounts. Never on someone else's app, not even to see if it's one of those five thousand: reading data without permission can be a crime, even if the door is open. If you think an app that isn't yours is exposed, tell whoever runs it.
1. Without login
The first check answers one question: what does someone with no account see? It takes a minute.
- Open your app in an incognito window, without logging in. That way the browser doesn't have your session and you're just any visitor.
- Right-click > Inspect > Network, then reload the page.
- Find a request that goes to .supabase.co and click it. There you see the project's address and the public key (publishable, or “anon” in older projects). It's normal to see it: it's made to live in the app.
Then open a terminal and run this line, with just those two pieces of information. Put in your project, your key and the name of one of your tables:
curl "https://YOUR-PROJECT.supabase.co/rest/v1/TABLE_NAME?select=*" -H "apikey: PUBLIC_KEY"
Try it on every table with people's data: profiles, messages, orders, emails. And do it on tables that really have data in them, because an empty table answers [] even when it's open: check in the Supabase dashboard first. If rows come back, anyone can read them. If a full table gives back [] or a permission error, that table doesn't answer passers-by.
2. As user A, B's data
The second check is the one people skip most often. The door can be closed to anyone who isn't logged in and open to anyone who is. Another minute.
- Create two test accounts, A and B.
- With each one, save some data: a profile, a note, an order.
- Log in as A and try to open B's rows, for example by changing the id in the request or in the page address.
If you can see them, the policies aren't there. Or they're there but they say “anyone logged in reads everything,” which isn't enough for personal data: the right check is on who owns the row.
3. The prompt for Claude Code
Once you know what's open, you have it closed. Open Claude Code in the project folder and paste this:
Check every table in my Supabase database: tell me whether Row Level Security is on and which policies it has. Where it's missing, turn it on and write the policies: each user reads, creates, updates and deletes only their own rows; tables that are public by choice, read-only. Never put the secret key (secret or service_role) in the app's code. Then run the test again: without login using the public key, and as user A on B's rows. Show me the before and after, table by table.
Every piece has a reason. “Reads, creates, updates and deletes” because on Supabase policies are written for each operation: closing only reading leaves the rest open. “Public by choice” because a catalog can be read by everyone, but that has to be your decision, not an accident. And “run the test again” because you check a policy by trying it, not by reading it.
Claude checks what it can see. If the tables are in the project's code, for example in the migration files, it finds them there. If you created them by hand in the Supabase dashboard, tell it which ones they are, or run the two tests by hand and give it the results. And if Claude Code asks for permission to run a command, read what it's about to do before you say yes.
How to read the before and after
You want the result in a form you can read at a glance. You can add “in a table like this” to the prompt and paste this template:
Table | RLS before | RLS after | No login before | No login after | A on B before | A on B after profiles | no | yes | rows | [] | rows | nothing
At the end you want to see three things: Row Level Security on for every table, no rows without login except in the tables that are public by choice, and A seeing nothing of B's. If a table doesn't come out that way, ask Claude why before you move on.
Two things worth knowing
Better closed than open
With Row Level Security on and no policies, nothing gets through the public key. So better closed than open, then open only what's needed. If a screen stops loading after the fix, don't switch security off: a policy is missing. Have that one added:
The [name] screen stopped loading data after you turned on Row Level Security. Find which policy is missing and add the narrowest one that does the job. Don't turn security off on any table. Then run both tests again, without login and from A to B.
The secret key
The secret key (secret or service_role) bypasses every policy. It lives only on the server: never in the app, never on GitHub. If it ended up in the app or in a repository, change it right away from the Supabase dashboard. Removing it from the code isn't enough: it stays in the history and with whoever has already seen it.
Not using Supabase?
Run the same test on your platform: without login, then from A to B. The names change, the idea doesn't. On Firebase, for example, the rules are called Security Rules: what to look for and the prompt to check them are in the PORTA guide.
Common mistakes
- Running the test while logged in. Use an incognito window, otherwise you see the data because it's you.
- Testing just one table. Every table has its own policies: test them all, starting with the ones that hold people's data.
- Trusting a [] that came from an empty table. An empty table answers [] even when it's open: test one that has data.
- Stopping at the no-login test. Do the A-to-B one too: that's where the “anyone logged in reads everything” policy hides.
- Turning off Row Level Security when a screen won't load. Add the missing policy and keep the rest closed.
- Trusting the fix without testing again. Run both tests again and look at the before and after, table by table.
Checklist
- No-login test, in incognito, on every table with people's data.
- A-to-B test with two test accounts.
- Row Level Security on for every table, with policies for reading, creating, updating and deleting.
- Public tables read-only, and only by choice.
- Secret key only on the server, never in the app.
- Both tests run again after the fix, with the before and after in front of you.
Frequently asked questions
Can I run the test on an app that isn't mine, to see if it's one of those five thousand?
No. Only on your own app and your own database. Reading other people's data without permission can be a crime, even if the door is open. If you suspect a problem, tell whoever runs the app.
I found an open table with real users' data. Is the fix enough?
The fix closes the door from now on; it doesn't undo what someone may have already read. Close it right away, change the secret key if it was exposed, and find out what obligations you have toward your users in the country where you operate.
When should I run it again?
After every new table and every time you change who can see what. It takes two minutes, and a new table doesn't inherit the policies of the others.