All articles

Security checklist for AI-built apps

By Magdalena Furman, 6 minute read

AI assistants write working code fast. They also skip the checks nobody asked for. That is why apps built with Cursor, Lovable, Claude Code or Copilot tend to fail in the same few places, and why a short checklist catches most of the serious problems.

This is the checklist I use when I audit an AI-built app. Every item is something you can check yourself in a few minutes. For each one I say what to look for and what a failure looks like.

1. Secrets in the code or the browser

  • Search the repository and its history for keys: git grep -nE "sk_live|AKIA|-----BEGIN" and git log -p -S "sk_live".
  • Check that no .env file is tracked: git ls-files | grep -E "\.env". Only .env.example should appear.
  • In Next.js, anything named NEXT_PUBLIC_ ends up in the browser. Make sure none of those hold a secret.
  • If a secret was ever committed, rotate it. Deleting it from the latest commit does not remove it from history.

2. Authentication on every endpoint

List every API route and server action, then open each one and ask: who may call this, and where does the code check it? A global middleware does not count unless you have read it.

git grep -nE 'export (async )?function (GET|POST|PUT|PATCH|DELETE)'
git grep -nE "'use server'"

A route that reads the user id from the request body instead of from the verified session is a critical problem. Anyone can send someone else's id.

3. Can user A read user B's data?

For every route that takes an id, check that the query also filters by the signed-in user or their organisation. findUnique({ where: { id } }) with no owner check means a logged-in user can change the number in the URL and read someone else's record. AI-generated code does this very often, because the happy path works.

4. Database access rules

If you use Supabase:

  • Every table needs row level security turned on, and no policy should be USING (true).
  • The service_role key must never appear in code that runs in the browser.
  • Run the Supabase security advisor. In one audit it found database functions that anonymous visitors could call, because they were SECURITY DEFINER and executable by the anon role. You can see that case in the example security report.

If you use Firebase, look for rules like allow read, write: if true.

5. Dependencies

npm audit --omit=dev

Fix what npm can fix automatically, then read what is left. In the same audit, the web framework itself had a known critical advisory with a non-breaking fix, and nobody had noticed.

AI assistants also sometimes suggest packages that do not exist, and attackers register those names. For any dependency you do not recognise, check when it was first published and who maintains it: npm view <package> time.created maintainers --json.

6. Webhooks

Stripe, GitHub, Clerk and similar services send webhooks. Your handler must verify the signature header with the provider's secret before it does anything. A webhook that trusts the request body lets anyone mark an order as paid.

7. Shared secrets and public APIs

If your frontend talks to your API with one shared secret in a header, ask what happens when it leaks. Compare it with crypto.timingSafeEqual, not ===, and plan to move to signed tokens or a private network.

8. Third-party tokens stored in plain text

If users connect their Google, Slack or ad accounts, you are storing long-lived tokens. Check whether they are encrypted at rest. A database leak then hands over access to every connected account.

9. Cost abuse and rate limiting

Any unauthenticated route that calls a paid API (an LLM, SMS, email) is a way to run up your bill. Check login, signup, password reset and anything that calls a model. Rate limits kept in a server's memory stop working once you run more than one instance.

10. Leftovers

Stack traces returned to the browser, debug routes, console.log of request bodies, and sample passwords in seed files that also run in production.

What a checklist cannot tell you

A scanner and a checklist find patterns. They cannot tell you whether your login is designed safely, or whether authorisation is right on every one of your endpoints. That needs someone to read the code. In the audit I mention above, the app had 65 endpoint files, and the quick scan flagged only the health check, which is meant to be public.

Run it on your own project

The free security skill runs a quick version of this checklist with your own AI assistant and explains what it finds in plain language. You can see its real output in the free example, and the full report it leads to in the security audit example.

If you would rather have someone else do it, I audit the code myself and write the report. See pricing.

Want to run these checks on your own project?