Data study

Exposed by default: what we found inside 2,511 vibe-coded apps

AI app builders are incredible. You describe an idea, and minutes later you have a real, deployed app with a login, a database, and a share link. The speed is the point. But speed hides a question almost nobody stops to ask: when you shipped that app, did you also ship the keys to its database?

To find out, we did something simple. We took publicly deployed apps from the vibe-coding ecosystem (Lovable, Replit, Vercel, v0, Base44, Firebase Hosting, Bolt, Netlify, and Cloudflare Pages), the kind that often store data in Supabase or Firebase, and we looked at each one exactly the way a curious stranger would. No login. No tricks. Just the same requests any visitor's browser already makes, using the same public key the app hands to every visitor. Then we counted. When a path answered, we also checked that the body really was what it claimed to be, not an app's home page served for every unknown URL.

The sample

We gathered public app URLs from free public sources only (mostly links developers put in public GitHub repositories and READMEs, plus Common Crawl) and ran our own scanner against them. We reached and scanned 2,511 live apps across nine hosting platforms:

  • Lovable: 504
  • Replit: 331
  • Vercel: 295
  • v0: 251
  • Base44: 237
  • Firebase Hosting: 230
  • Bolt: 224
  • Netlify: 220
  • Cloudflare Pages: 219

603 of them ship a detectable Supabase configuration to the browser and 194 ship a detectable Firebase configuration. That is normal, and it is also exactly the part that has to be locked down.

Four panels by platform: reachable sample size from Lovable 504 down to Cloudflare Pages 219; open-table rate among Supabase apps; strict .env, source map, and secret exposure, led by Base44 source maps near 60% and Firebase Hosting near 14%; and the share of apps graded F.
The sample at a glance across all nine platforms. Open-table rates for Replit, Base44, and v0 rest on very few Supabase apps and are not comparable.

Five things we found

Bar chart of exposures across 2,511 reachable apps after strict body checks: open database table 4.8%, secret in shipped JavaScript 0.5%, source map exposed 8.2%, .env exposed 0.04%.
Share of the 2,511 reachable apps with each exposure, after strict body checks.

1. About one in five Supabase apps leaves a table wide open. 120 apps (4.8% of all reachable apps) returned real database rows to a request that carried nothing but the public key. Among the 603 apps with a detectable Supabase backend, the rate is 19.9%. Lovable (21%), Cloudflare Pages (24%), and Netlify (23%) sit near that band, with Bolt at 16% and Vercel at 11%. The usual cause is a single skipped step: Row Level Security was never turned on, so the public key can read everything.

Bar chart of Supabase apps with an open table by platform: Lovable 21% of 297, Cloudflare Pages 24% of 93, Netlify 23% of 75, Bolt 16% of 64, Vercel 11% of 55, v0 11% of 9, Firebase Hosting 0% of 5.
Among apps with a Supabase backend, 19.9% (120 of 603) had at least one table returning rows to the public key.

2. Public keys are not locks. Shipping a Supabase or Firebase config to the browser is expected. Those keys are designed to be public. The bug is assuming the key is the lock. It is not. The lock is your database rules, and this study is really a story about missing rules.

3. Real .env files are rare. Once we required a real env file body, we found exactly one app in the whole sample serving a downloadable .env. Many hosts answer every unknown path, including /.env, with the app's home page and a success status. If you only check the status code, you will fool yourself.

4. Source maps are real on some platforms. 205 apps (8.2%) ship a parseable production source map, which hands anyone your original code. The signal is platform-shaped: Base44 leads at 59.5%, Firebase Hosting follows at 14.3%, and most other platforms sit under 5%.

5. Real secrets are uncommon but severe. 12 apps (0.5%) shipped a secret matching a strict provider pattern in their JavaScript, such as a Supabase service-role key. A service-role key ignores every database rule you set. It is the master key, and it should never reach the browser.

Left, pie chart of detected backend: Supabase 594 apps, Firebase 185, both 9, neither detected 1,723. Right, bar chart of scan grades: A 1,091, B 358, C 143, D 416, F 503.
Detected backends and approximate scan grades. 503 of 2,511 apps (20.0%) earned an F, and 1,091 (43.4%) earned an A.

Why this happens (and why it is not your fault)

When a tool generates and deploys an app in one click, the secure default has to come from the tool, not from a developer who may not know Row Level Security exists. HTTPS is on by default, so almost everyone is safe there. Database rules are not on by default in the same way, so wherever Supabase shows up in the browser, open tables show up too. The gap between "it works" and "it is safe" is invisible until someone looks, and most people never look.

Check your own app in ten seconds

That is exactly why VibeLocked exists. Paste your app's URL into our free scanner and it runs these same read-only checks against your app and shows you, in plain language, what a stranger can see and the exact prompt to fix it.

Scan a live app

How we did this, and the lines we did not cross

Every check was anonymous and read-only: the same GET requests a browser makes, using the public key the app already ships. We never logged in, never wrote or changed any data, and never stored row contents. We did not store secret values, and we are not naming a single app. We hashed every hostname and are publishing aggregate numbers only. The goal is to show the size of the problem and help people fix their own apps, not to point at anyone's.

Sample: 3,501 distinct app URLs, 2,511 reachable, scanned 2026-10-18 to 2026-10-19 (Pacific time), with a strict re-fetch of every positive finding. Methodology and ethics notes available on request.

Methodology

Sample. We collected 3,501 distinct candidate app URLs from public GitHub code search, public deploy links, and Common Crawl, then scanned them. 2,511 were reachable. Every platform in the study has more than 200 reachable apps. Percentages use the 2,511 reachable apps unless stated.

Read-only, anonymous checks only. Every request was a GET, HEAD, or OPTIONS request with no login and no cookies, using only the public keys each app already sends to its visitors. We never wrote or changed data. Secret values were masked and never stored, and hostnames were kept only as a hash.

Strict verification. A success status alone never counted. Every positive was re-fetched and kept only if the body passed a strict check:

  • .env: the body must not be HTML and must contain at least one KEY=VALUE line.
  • Source maps: the body must parse as JSON with a numeric version plus a sources array or a mappings string.
  • Open tables: the response must be a PostgREST JSON array with at least one row under the public anon key. An empty array does not count, and apps that no longer return rows were cleared.
  • Secrets: only strict provider-style patterns count, such as Supabase service-role keys, Stripe, AWS, GitHub, and Groq keys, private key blocks, and database URLs with credentials. Generic high-entropy strings do not.

Caveats.

  • This is a point-in-time pass. A rescan days later would differ as apps are fixed or abandoned.
  • The open-table check can undercount (tables we never named) but does not overcount, because a hit means real rows came back to the public key.
  • "Backend not detected" does not mean no backend. It can mean a static site or a backend the client code does not reference.
  • Replit, Base44, and v0 apps rarely expose a Supabase client (3, 2, and 9 apps), so their open-table rates are not comparable to other platforms.
  • Letter grades are approximate.