16,000 Supabase apps are serving readable user data, and the common thread is Row Level Security that was never switched on
Security firm UpGuard found more than 16,000 Supabase-backed apps serving readable tables to anyone on the web, over half of them holding personal data. The root cause is Row Level Security left off on API-created tables, a default that AI coding agents rarely go back and fix.
Security firm UpGuard says it found more than 16,000 Supabase-backed applications serving readable database tables to anyone who asked, with over half of them holding personal data. The finding is not a Supabase vulnerability, and that is the uncomfortable part: nearly every exposed app was built exactly the way the platform and the AI agents that recommend it encourage, and shipped without the one setting that would have closed the door.
What UpGuard found
UpGuard started from roughly 300,000 domains that carried Supabase fingerprints,
identified through technographic scans and by reading the Supabase project URLs
and API keys sitting in public client-side JavaScript. It then probed each one
for a users table. On 16,326 of them the table came back readable. More than
half of those contained personally identifiable information, a smaller share
exposed passwords or authentication tokens, and a few leaked payment data.
The concrete examples are worse than the numbers. An Indian content platform exposed 65,467 users along with passport and national ID details. A Philippines OTP service leaked more than 100,000 SMS messages, including one-time passcodes. A US valet service exposed license plates and names for tens of thousands of customers. A Canadian immigration service leaked around 5,000 records, 884 of them with plaintext passwords. These are live apps with real users, not test projects.
Why the default does the damage
Supabase puts a Postgres database behind an auto-generated REST API, and it hands your app a publishable “anon” key to talk to it. That key is designed to live in the browser. It is only safe there because Row Level Security, Postgres’s per-row access control, is supposed to stand between the key and the data.
The gap is in what happens by default. As Supabase’s own documentation puts it, “A table in an exposed schema without RLS is readable and writable by any role with a grant on it.” Tables created through the dashboard prompt you to enable RLS, but tables created through the API, which is how programmatic and agent-driven workflows build schemas, do not force the issue. Enable RLS and, in Supabase’s words, “no data is accessible through the API when using a publishable key, until you create policies.” Leave it off and the publishable key in your bundle is a public read grant on the whole table. The failure mode is not exotic. It is the difference between one setting on and off.
The AI-agent angle
The reason this reads as a 2026 story rather than a recurring database footgun is who is writing the schema now. UpGuard points directly at AI coding agents, noting that Supabase “is the database product most recommended by Claude Code” and that agents tend to favor tools they were reinforced to use well. An agent asked to stand up a backend will create tables through the API, wire up the anon key, and produce a working app. Turning on RLS and writing policies is a separate, easy-to-skip step that a prompt focused on “make it work” rarely reaches.
That is the practical shift worth naming. A generated backend can pass every functional test a developer runs, load fast, and demo cleanly, while shipping with its front door open. The convenience that makes Supabase a natural fit for agent workflows is the same convenience that produces the exposure, because the agent optimizes for a running app, not a locked-down one.
What to do about it
The remediation is unglamorous and immediate:
- Audit every table in an exposed schema for RLS. In the Supabase dashboard, any table without RLS enabled is a candidate for exposure, and the advisor flags them.
- Enable RLS and write policies. RLS on with no policies denies all API access, which is the safe starting point; add policies to grant exactly what each role needs.
- Treat the anon key as public, because it is. It is not a secret and never was, so it cannot be your access boundary. Do not confuse it with the service-role key, which must stay server-side.
- Do not trust a generated backend’s security posture by default. If an agent built the schema, review the access model before real users touch it.
What to watch
The open question is whether platform defaults move. UpGuard’s framing is that, like Amazon S3 and GitHub before it, Supabase may need to “rebalance the equation” so the secure configuration is the automatic one rather than the extra step. Supabase’s position, per its response to TechCrunch, is that projects are secure by default and that customers control their own configuration, which is accurate for dashboard-created tables and less reassuring for API-created ones. The broader signal for developers is that as more schemas get written by agents than by people, “secure by default” has to mean secure without a follow-up step, because the follow-up step is exactly what is being skipped at scale.
- Everything, everywhere: systemic data exposure in Supabase apps, with methodology and case examples (UpGuard research) www.upguard.com
- Some Supabase customers are publicly exposing reams of people's data to the web, including Supabase's on-record response (TechCrunch) techcrunch.com
- Row Level Security, official Supabase documentation on the default and the fix supabase.com