The 7 Security Checks Every AI-Built App Needs Before Launch
Shipping an app that an AI coding tool generated is not the same problem as shipping an app you typed line by line. The code usually runs. The gap is everything the generator assumed on your behalf: that you would turn on row-level security later, that the key it wired into the front end was the safe one, that someone would review the storage bucket before real files landed in it.
A launch decision needs evidence. Below are the seven checks that produce it, and the proof each one should leave behind.
1. Database access rules
The single highest-impact check. For every table your app can reach, identify the exposed API path, inspect schema and table grants, and review row-level security together with every policy that applies to the request role. RLS enabled with a using (true) policy can allow all rows for that operation; policy existence alone is not proof of isolation.
Evidence to keep: exposed schemas, relevant grants, whether RLS is on, and the applicable policy expressions. For roles subject to RLS, an enabled table with no applicable policy uses default deny. RLS disabled alone does not prove public access; the request still needs an exposed path and sufficient privileges. If those allow access, there is no row-policy filter protecting the rows.
2. Secrets and keys
Look for service-role keys, provider tokens and private API keys that ended up in client-side bundles, committed .env files, or git history. Third-party scans of AI-built apps keep finding admin keys in front-end JavaScript (one 29-app sample put it at roughly one in four). A key in a shipped bundle is public forever, so rotation — not deletion — is the fix.
Evidence to keep: the file and line of every match, plus the rotation timestamp.
3. Authentication and authorization
Confirm every private route is gated on the server, not only in the UI. Check that roles live in their own table rather than on a profile row a user can edit, that password recovery works end to end, and that email confirmation matches your intent.
Evidence to keep: an unauthenticated request to a protected endpoint, and the status code it returned.
4. Storage
Buckets default to whatever the generator chose. For each bucket: is it public, and does that match what it holds? Signed URLs for private files, path-scoped policies for user uploads, and a size/MIME limit so an upload field is not a free CDN.
5. HTTP security headers
The cheapest hardening you will ever do, and the most consistently missing. A content security policy, Strict-Transport-Security, X-Content-Type-Options, a referrer policy and a frame-ancestors rule. Headers do not fix a broken database, but their absence turns a small bug into a session-stealing one.
6. Dependencies
Resolve the lockfile against advisory data and look at what is actually reachable from your code. A critical advisory in a build-only dev dependency is not the same risk as one in your request path — and treating them identically trains you to ignore both.
7. Deployment configuration
Debug mode off, source maps not served publicly, environment variables scoped to the right environment, preview deployments not pointing at the production database, and webhook endpoints verifying signatures before they trust a payload.
The verdict is the point
Once all seven have fresh evidence, you get one of four honest answers:
| Verdict | Meaning |
|---|---|
| Ready | All seven fresh, no unresolved critical or high findings |
| Needs review | Evidence complete, only medium or low findings left to decide |
| Blocked | Evidence complete, at least one critical or high finding open |
| Insufficient evidence | A required check never ran, failed, or went stale |
The fourth row is the one most tools quietly skip. If a check has not run, the correct output is not a green badge and not a score — it is "we do not know yet." Everything else is a guess wearing a launch button.
Use these seven checks as a launch evidence record: note what ran, what it covered, who reviewed the result, and what remains unknown. A launch decision should be re-checked against current evidence instead of remembered.