The 20% AI-built apps are missing, and how to find it in a second
AI coding tools get an app to the part where it demos. Then it stops. What is missing is boring: an API route with no auth check, a key sitting in the browser bundle, a query built by string concatenation, TLS verificati
AI coding tools get an app to the part where it demos. Then it stops. What is missing is boring: an API route with no auth check, a key sitting in the browser bundle, a query built by string concatenation, TLS verification switched off so an integration would finally connect. None of that shows up until a real user, a real bill, or a real attacker does.
I did not want to guess how common it is, so I measured it.
The measurement
I wrote a small deterministic scanner (stdlib Python, no dependencies, no network) for ten specific production failure classes, then ran it over 13 popular open-source AI-app starter repos. Shallow clone, default branch, unmodified trees.
- 4 of the 13 repos came back clean.
- The other nine held 101 findings, 50 of them critical.
- The single most common defect: an API route with no auth check, in 6 of the 13 repos.
- Then: a secret-ish value shipped to the client bundle through a public prefix (5 repos), untrusted content rendered as raw HTML (5), a
TODOstanding where the auth check should be (1), wildcard CORS on an authenticated surface (1), TLS verification disabled (1).
These are popular, well-maintained repos. The point is not that their authors were careless. The point is that the default path a framework or a generator hands you is the insecure one, and the quickest fix to make a request stop failing is also the insecure one. That is why the defect repeats across unrelated projects.
The full method and the aggregate table are in the report: https://vibechecksai.github.io/vibecheck/REPORT.md
The failure classes worth checking first
-
Secrets shipped to the browser. Anything with a
NEXT_PUBLIC_orVITE_prefix ends up in the client bundle. If the value is a real API key, it is public. Fix: rename it, call it server-side, rotate the key. - Routes with no auth guard. A handler that reads the session but never rejects a missing one is a public endpoint. Fix: one guard at the top of the handler.
- String-built SQL. Template literals around user input are injection. Fix: parameterised queries.
-
TLS verification off.
rejectUnauthorized: falseand friends. Fix: fix the certificate, not the check. -
Cookies without flags. Session cookies missing
HttpOnly,Secure,SameSite. Fix: set them at the framework level. -
Default
.envnot ignored. A committed.envis a credential leak that survives key rotation in git history. Fix:.gitignoreplus a rotated key. -
Raw HTML rendering.
dangerouslySetInnerHTMLand friends on user content. Fix: sanitise, or do not render HTML. -
eval/execon anything derived from input. Fix: delete it. -
Wildcard CORS on an authenticated surface.
Access-Control-Allow-Origin: *with credentials is not a configuration shortcut, it is a hole. Fix: allowlist. - TODOs on auth and payment paths. "Add auth later" ships. Fix: do it before the next deploy.
None of these take a day to fix. They take an afternoon, and only if you know they are there.
How to check your own app in a second
The scanner is free and MIT licensed. It needs no install:
git clone https://github.com/vibechecksai/vibecheck
python3 vibecheck/vibecheck.py .
Output looks like this:
vibecheck — 8 findings: 2 critical, 4 high, 2 medium
[CRITICAL] client-exposed-secret lib/client.ts:1
An API key is exposed to the browser bundle.
fix: rename without the public prefix; proxy it server-side.
[CRITICAL] env-not-ignored .env
A .env file exists but is not in .gitignore.
[HIGH ] route-without-auth app/api/users/route.ts:1
A route handler with no auth check.
[HIGH ] tls-verification-off lib/payments.ts:3
TLS verification is disabled.
It also runs as a GitHub Action, so the check happens in CI instead of after the breach: https://github.com/marketplace/actions/vibecheck-ai-app-scanner
A finding is a pattern, not proof of exploitability. It is a prompt to look at one line, with the fix written next to it.
If you would rather hand it off
Fixing these is the part most people skip, so I do it as a flat-fee, fixed-scope job: criticals and highs fixed in your repo, plus a re-scan showing zero critical and high findings in the agreed scope. That re-scan is the receipt. Details: https://vibechecksai.github.io/vibecheck/order.html
Free scan, no strings
Send a repo URL to [email protected] and I will run the scan and reply with the findings, whether or not you ever pay for anything. If the report is clean, that is a useful answer too.
Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.