Security research2 min read
Exposed secrets and personal data in vibe-coded apps
A passive scan of 5,600 public apps turned up hundreds of live secrets and real personal data. Most of it was sitting in places any visitor's browser already downloads.
Key takeaways
- Escape's passive scan of 5,600+ public vibe-coded apps found 2,000+ high-impact vulnerabilities, 400+ exposed secrets, and 175 PII instances.
- Secrets leak through client bundles, environment variables with public prefixes, and verbose API responses.
- Personal data leaks when list endpoints return whole records instead of the fields the screen needs.
- Check what the browser receives, not just what the repository contains.
What Escape found
Escape analysed more than 5,600 publicly available apps built on Lovable, Base44, Create.xyz, Vibe Studio, and Bolt.new. They reported over 2,000 high-impact vulnerabilities, more than 400 exposed secrets, and 175 instances of exposed personal data, including medical records, IBANs, phone numbers, and emails. The full report breaks this down.
Two points from their methodology matter for reading the numbers. The scans ran in a passive mode that avoided aggressive payloads, so the authors call the results a lower bound. And most vulnerabilities were reachable without any authentication at all, including Supabase service keys sitting in frontend bundles.
Where secrets leak
- Client bundles. A key referenced in frontend code is compiled into JavaScript that every visitor downloads.
- Public environment prefixes. Frameworks expose variables named
NEXT_PUBLIC_*orVITE_*to the browser by design. A private key with that prefix is public. - API responses. Config endpoints, error payloads, and debug routes sometimes echo credentials back.
- Static files left in the deploy, such as
.env, backups, or source maps.
The usual cause is not carelessness. A model asked to make a feature work will put the key wherever the call happens, and in a frontend-first app that is the browser.
Where personal data leaks
Personal data leaks less through bugs than through over-sharing. A list endpoint returns full user records when the screen needs only a name. A profile route returns the email of whoever's ID is in the URL. An admin route is guarded in the menu but not on the server.
Each of these looks fine in the interface, because the interface only renders what it needs. The extra fields are visible only in the network response.
A checklist for your app
- Search your built bundle, not just your source, for key prefixes such as
sk_,sk-, andAKIA, and for long base64 strings. - Move third-party calls that need a private key behind a server route.
- Rotate any key that has ever shipped to a browser. Removing it from code does not remove it from caches or archives.
- Open the network panel on each screen and read the raw responses. Remove fields the screen does not use.
- Request
/.env,/debug, and your source map paths on the production host. They should return 404.
Where Routelint fits
Routelint's secret and PII exposure suite classifies every captured response for tokens, card numbers, emails, and stack traces, and its sensitive paths suite probes for files like /.env. It reads what the running app returns, which is where these leaks actually happen. It does not scan your repository or your dependency tree.
Questions
- Is it safe to put an API key in a NEXT_PUBLIC environment variable?
- Only if the key is designed to be public, such as a publishable payments key. Any variable with a public prefix is compiled into browser JavaScript and visible to every visitor.
Routelint records the API calls your running app makes, then replays them with no session and as a second account. One scan needs no account.
Sources
- The state of security of vibe-coded apps — Escape
- How we discovered vulnerabilities in apps built with vibe coding — Escape
Published November 1, 2026 by the Routelint team.
