You built an app over a weekend with Lovable, Bolt, Replit or Cursor. It works, the demo looks great, and you are about to share the link. Before you do, spend an hour on the boring stuff. AI tools are good at making things work. They are much less good at making things safe, because "safe" never shows up in a demo.
This is the checklist I run before any AI-built app gets real users. It is ordered by how often the problem bites, and none of it needs a security background.
1. Look for secrets in your front end
Anything your browser downloads is public. In Vite projects, every variable starting with VITE_ ends up in the JavaScript bundle. In Next.js it is NEXT_PUBLIC_. If a Stripe secret key, an OpenAI key or a Supabase service_role key sits behind one of those prefixes, anyone can copy it.
Open your deployed site, view the source, and search the JavaScript files for sk_, service_role and api_key. If you find a real secret, rotate it first and then move the call to a server function.
2. Check your database from the outside
If you use Supabase, the anon key is meant to be public. That is fine only when Row Level Security (RLS) is switched on for every table in the public schema and the policies are strict. Run this in the SQL editor:
select tablename from pg_tables
where schemaname = 'public' and not rowsecurity;
Every table it returns can be read by anyone holding your public key. Turn RLS on, then write policies such as using (auth.uid() = user_id). Policies that say using (true) are RLS in name only.
3. Test as a second user
Create two accounts. Log in as user A, copy the id of one of A's rows, then log in as user B and try to fetch it. If B can read it, your policies only check "is logged in" and not "is the owner". This is the single most common leak in AI-generated apps, and the anon test above will not catch it.
4. Don't leave files lying around
Visit /.env, /.git/config, and any backup file names your project might have produced. Each should return 404 or be blocked. Also check that the build output does not ship source maps you did not intend to publish.
5. Payments: trust the webhook, not the redirect
If you take payments, do not mark an order as paid because the user landed on a "thank you" page. Anyone can type that URL. Confirm payment from the provider's webhook, verify the signature on every event, and make the handler idempotent so a retry does not grant access twice.
6. Auth settings
Set the Site URL and allowed redirect URLs in your auth provider to your real domain, not a wildcard. Make sure password reset and email confirmation actually work in production, with a real inbox.
7. Add limits
Signup, login, password reset and any endpoint that sends email or calls a paid API need rate limits. Without them, one script can burn your monthly API budget in an afternoon. Set a spending cap or alert on every paid service.
8. Headers and HTTPS
Force HTTPS and add the basic security headers: Strict-Transport-Security, Content-Security-Policy (even a loose one), X-Content-Type-Options and a frame policy. Hosts like Vercel and Netlify let you set these in a config file.
9. Click through your own app
Sign up, log in, reset a password, pay, delete your account, and open every page. Broken links and 500 errors are not security holes, but they are the first thing a stranger sees.
10. Have a way back
Turn on backups for your database and test one restore. Keep your code in Git and commit before each big AI change, so a bad edit is a one-command undo.
What a checklist cannot do
None of this is a penetration test, and I would not call any automated check one. A checker looking at your site from the outside cannot see behind your login, and it cannot judge your business logic. Steps 3, 5 and 6 above need you to try things by hand.
Full disclosure: I built DeployVet, a free check that does steps 1, 2, 4, 8 and 9 for you from the outside, because those steps are easy to skip. Use it, use another tool, or just use this list. The point is to look before your users do.
Top comments (0)