Most people have never watched a security scanner run on the kind of app they build in an afternoon with an AI. It is not dramatic. There is no alarm. It is a quiet list of the specific lines where a secret got left in the open or a safety check got switched off. That list is the whole point, so here it is, one finding at a time, on a small demo app that looks exactly like the ones we scan by the thousand.
Finding 1: a database key sitting in the source
Severity: high. This is the one we find more than any other, in every study we have run across every AI coding tool.
// src/integrations/supabase/client.ts const SUPABASE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...";
The backend key is written straight into a committed file as a string. Anyone who can read the repository, or its git history, holds the key. Without Row Level Security configured on every table, that key is a direct line into the whole database: read every row, write to any of them. The fix is to move it into an environment variable and rotate the exposed one, because it is already in your git history even after you delete the line.
Want to see exactly what Prbl flags? Watch it scan a demo app, no repo or account needed.
See a live scan →Finding 2: certificate checks turned off
Severity: high. A single option that quietly removes the protection against someone intercepting your database or API traffic.
// server/db.ts
ssl: { rejectUnauthorized: false }This usually gets added to make a connection work against a local or self-signed certificate, and then it ships. With verification off, a machine sitting between your app and the server can read or alter everything on the wire. The fix is to remove the option and, if a local certificate is the real problem, supply the CA certificate instead of disabling the check.
Finding 3: a token built from predictable randomness
Severity: medium. It looks random. It is not random enough for the job it was given.
// lib/token.ts const token = Math.random().toString(36).slice(2);
Math.random() is not a cryptographic source, and its output can be predicted. When it is used to mint a session token, a password-reset code, or an OAuth state value, an attacker who can guess the sequence can forge valid ones. The fix is one line: use crypto.randomUUID() or crypto.getRandomValues() for anything security-sensitive.
Finding 4: a secret compared the leaky way
Severity: medium. The comparison works. It also tells an attacker how close their guess was.
// app/api/verify/route.ts
if (providedToken === process.env.API_SECRET) {A plain === on a secret returns as soon as it hits the first character that does not match. Measured across many requests, that timing difference leaks the secret one character at a time. The fix is a constant-time comparison such as crypto.timingSafeEqual(), which always takes the same amount of time regardless of the input.
Finding 5: the request body going into the logs
Severity: low, and the easiest to overlook because it feels harmless.
// src/utils/logger.ts
console.log('auth payload', req.body);Request bodies on an auth route carry passwords and tokens. Logging them verbatim copies those secrets into every log aggregator and error tracker the app talks to, where they sit in plain text far longer than anyone intends. The fix is to redact the sensitive fields before logging, or log only the metadata you actually need.
None of these were the AI's fault
Here is the part worth sitting with. A demo app like this is competently built. The routing is clean, the logic is reasonable, the app runs. The five findings are not reasoning mistakes an AI made and a smarter one would avoid. They are the small shortcuts a human takes to get something working: paste the key in for now, turn the cert check off to get past the error, reach for the Math.random that is right there. We measured this directly across five AI coding tools and the high-severity flaw rate was flat across all of them, because the flaws come from the workflow, not the model.
Which is exactly why a scan is worth thirty seconds: the issues are boring, predictable, and easy to fix once something points at the line. The hard part is only ever noticing.
Now run it yourself
Everything above is one demo app. The interesting version is the scan of real code. You can watch the exact scan from this post run live, and then point it at any public repository, your own or one you are curious about, with no account and no card.
If you want the bigger picture behind these five patterns, we have scanned nearly 2,000 AI-built apps and the same secret keeps leaking in every corpus. This teardown is just what that looks like up close.