row level security supabase

16,326 Apps Are Leaking Their Users’ Data. Here’s the Setting That Stops It.

TL;DR: Security researchers at UpGuard scanned roughly 300,000 domains and found 16,326 Supabase databases with tables anyone could read — names, addresses, phone numbers, passwords. Nothing was hacked. The apps were simply built without row level security switched on, a one-line setting that AI coding tools frequently skip. If you’ve built an app that stores anything about other people, check this today.

What actually happened

On 25 September 2026, TechCrunch’s security editor Zack Whittaker reported research from the security firm UpGuard into apps built on Supabase — the database service sitting behind a very large share of apps made with AI builders.

UpGuard’s researcher Greg Pollock scanned roughly 300,000 domains. According to RuntimeWire’s report, 16,326 of them had at least one database table that any member of the public could read — no password, no break-in, nothing more than knowing the address.

What was sitting in them, per TechCrunch: publicly accessible names, addresses, phone numbers and user passwords, plus a smaller number of authentication tokens. The specific examples included:

Exposed databaseWhat was readable
A US valet serviceThousands of customer licence plates
An immigration and relocation serviceCustomer contact information
An Indian adult streaming sitePrivate conversations
An African government consulate in FranceConsular records
A virtual SIM farmIntercepted account-verification texts

TechCrunch’s framing is the part worth repeating, and note where it points — at vibe-coded apps specifically: the findings “highlight how vibe-coded apps and websites can spill or expose sensitive data through basic misconfigurations and improper security.”

Two things to hold on to before anyone panics. 16,326 out of roughly 300,000 is about 5% — this is not “every app built with AI is leaking”. And nobody was hacked. There is no Supabase vulnerability here. Every one of these databases did exactly what it was configured to do — which, without row level security, is to answer any question anyone asks it.

What row level security actually is

Here is the whole idea in one sentence you don’t need to be a developer to follow.

A database table is a spreadsheet. Row level security is the rule that says which rows a given person is allowed to see. Without it, the answer is “all of them”.

Supabase’s own documentation puts it more bluntly: “A table in an exposed schema without RLS is readable and writable by any role with a grant on it.” Read “any role” as anyone at all, including a stranger with a browser.

The reason this bites specifically in apps built by non-developers is that nothing looks wrong from the front end. Your app shows each user their own orders, their own messages, their own bookings, because your app asks for exactly that. Row level security is about what happens when someone skips your app entirely and asks the database directly. That request never touches your screens, so no amount of clicking around your own site will ever reveal the problem.

Why AI-built apps skip row level security

This is the bit that explains 16,326 rather than 16.

When you create a table by clicking through the Supabase dashboard, you get a prompt nudging you toward row level security. When a table is created by a script or an AI agent, you don’t. RuntimeWire states it plainly: “Tables created programmatically, the route commonly used by coding agents, do not enable RLS by default.”

And that is precisely how tables get made when you describe an app in plain English and a tool builds it. You never see the table being created, so you never see the setting you didn’t tick.

There is a second layer that catches people out even when they have heard of this. Grants and policies are different things. A grant decides whether a role can touch the table at all; a row level security policy decides which rows it sees. Supabase’s documentation is explicit that turning one on does not undo the other: “Adding policies doesn’t take those grants back.” So “I added a policy” is not the same as “it’s locked down” — the grant has to go too.

What Supabase says — and what its own docs say

Supabase’s Chief Information Security Officer Bil Harmer told TechCrunch the company had not seen UpGuard’s research, described Supabase projects as “secure by default”, and called security “a shared responsibility” between the company and customers who control how their own projects are configured.

That is a reasonable position, and the “shared responsibility” part is simply true — no database provider can decide who should be allowed to read your customer list, so row level security is always going to be a decision only you can make. But it’s worth putting one detail beside it. Supabase’s documentation states that “on existing projects, a new table in `public` starts with every privilege already granted to all three roles” — including the anonymous one. Secure by default is doing some work in that sentence.

Supabase is fixing exactly this, and started well before the research landed. Its changelog entry of 28 April 2026 announced that new tables would stop being exposed to the Data API automatically:

  • 28 April 2026 — the new behaviour became available to opt into
  • 30 May 2026 — it became the default for all new projects
  • 30 October 2026 — it will be enforced on existing projects

Supabase’s own stated reason for the change names the problem directly: “Agents, CLI scripts, and AI platforms create tables too, and many of those operations do not have a human reviewing the diff.” The company saw this coming five months before the headline.

The catch for you: if you built your app before 30 May 2026, you are on the old defaults until the end of October. Don’t wait for it.

How to check your app today

  1. Open your Supabase dashboard and go to the Table Editor. Every table shows whether row level security is enabled. Anything showing as unrestricted is readable by the public.
  2. Turn it on for each one. In the SQL editor that is a single line per table — `alter table public.your_table enable row level security;` — or one toggle in the dashboard.
  3. Add a policy. Row level security with no policy blocks everyone, including your own users, which will break your app until you say who’s allowed what. Ask your AI tool: “add an RLS policy so users can only read and edit their own rows.”
  4. Do the second-user test. We said this when Lovable bought Sutro four days ago: make a second account and try to reach the first account’s data. It takes ten minutes and catches the single most common serious mistake in AI-built apps. Today there are 16,326 databases’ worth of evidence for it.
  5. Make it part of the build, not the cleanup. Add “enable row level security and write an owner-only policy on every table” to your standing instructions to whatever tool you use, so new tables arrive locked.

Who should care (and who shouldn’t)

  • Running a live app that stores anything about other people: this is today’s job. Not this week — today.
  • Building an internal tool for your business: same answer. “Only our staff use it” is not a security setting; row level security is, and your database URL is exactly as guessable as anyone else’s.
  • Building a landing page or brochure site with no database: nothing to do. If you’re not storing user data, there’s nothing to leak.
  • Still learning, projects not public: learn this now, while the stakes are zero. Row level security is the single highest-value hour a non-developer can spend on security.
  • Not on Supabase: the specific research is about Supabase, but the principle isn’t. Every backend has an equivalent, and the same AI-created-it-so-nobody-checked gap applies.

Our take

Yesterday we wrote about apps built by non-developers drawing close to a billion visits a month. This is the invoice for that number.

These are the same apps. The category has crossed from demos into things real people put their phone number into, and this research is the first large-scale measurement of what that costs when one setting gets missed. 5% isn’t a catastrophe — but 16,326 is a lot of people’s licence plates.

The honest read isn’t “AI coding tools are unsafe”. It’s narrower and more useful: the tools automate the building and not the securing, and row level security is the clearest example of the gap. A human clicking through a dashboard gets nudged. An agent running SQL doesn’t. That is a defaults problem, Supabase has been fixing it since April, and until 30 October the fix doesn’t reach the app you already built.

We’d also resist the urge to blame the people who built these apps. Nobody was careless — they were given a table that was open by default and no reason to think otherwise. The lesson is the second-user test: ten minutes, no technical knowledge, and it would have caught most of these 16,326.

Not sure which builder fits what you’re making — or how much security it hands you? Take the 60-second Vibe Coding Tool Finder quiz →

FAQ

What is row level security?

Row level security is a database rule deciding which rows each person can see. Without it, any table reachable from the internet can be read by anyone who knows its address, regardless of what your app’s screens show. Supabase calls it RLS, and it’s off by default on tables created by scripts or AI agents.

Was Supabase hacked?

No. UpGuard found no vulnerability in Supabase itself. The 16,326 exposed databases were misconfigured by their owners — tables left readable because row level security was never switched on. Supabase’s CISO said the company hadn’t seen the research and described projects as secure by default, with security a shared responsibility.

How do I know if my vibe-coded app is affected?

Open your Supabase Table Editor and look for tables marked as unrestricted. Then create a second account on your own app and try to reach the first account’s data. If you can see someone else’s records, row level security is missing or your policy is wrong — and the public can see them too.

Similar Posts