Security checklist for an app built with an AI tool, before you launch

Checked on

Most problems in apps made with Lovable, Bolt, Cursor, Replit or v0 come from a few places: database tables without rules, secret keys placed in the web page, payment webhooks that aren't verified, and private files left public. Go through the eight checks below before you share the link. Three of them come with a prompt you can paste into your AI tool.

Who this is for

You built the app with an AI tool, you don't read code every day, and real people are about to sign up or pay. You don't need a full audit to fix the common problems. You need to check a short list, in order.

The checklist

1. Every database table has rules (Supabase RLS)

If your app uses Supabase, the browser talks to the database directly. Supabase's own docs say a table without Row Level Security (RLS) “is readable and writable by any role with a grant on it”, and tell you to “enable RLS on every table”. Rules decide who can read, add, change and delete each row.

Check: in Supabase, open Table Editor. Any table marked as without RLS needs it turned on, and then needs a rule for each action your app uses.

Fix prompt:

List every table in my Supabase project and say whether Row Level Security is on. Turn it on for every table. Then add policies so each signed-in user can only read and change their own rows, and say which tables are meant to be public and why. Don't use the service role key in any code that runs in the browser.

More detail: Is your Supabase anon key safe in the browser? and Supabase “permission denied for table”.

2. No secret keys in the web page

Anything the browser loads, anyone can read. In apps built with Vite (Lovable, Bolt and many others), every setting that starts with VITE_ is copied into the page code. Vite's docs say these “should not contain sensitive information such as API keys”. In Next.js the same is true for NEXT_PUBLIC_.

Keys that must never be in the page: the Supabase secret or service_role key, the Stripe secret key (sk_live_...), and OpenAI or Anthropic keys. The Supabase publishable (anon) key and the Stripe publishable key (pk_live_...) are meant to be public.

Fix prompt:

Search my whole project for secret keys: Supabase service_role or sb_secret keys, Stripe sk_live or sk_test keys, OpenAI and Anthropic keys. Any that are used in code that runs in the browser, or in a VITE_ or NEXT_PUBLIC_ setting, move into a backend function (for example a Supabase Edge Function) and read them from server-side secrets. Tell me which keys I need to rotate.

More detail: OpenAI API key exposed in the frontend and Supabase service role key exposed in the frontend.

3. Rotate any key that was ever exposed

Moving a key out of the code is not enough if it was already published. Old versions of your site and your code history may still contain it. Create a new key with the provider, put it in your server-side secrets, then delete the old one.

4. Stripe webhooks are verified

If Stripe tells your app “this customer paid” through a webhook, your app must check that the message really came from Stripe. Stripe's docs say to verify each request “using the Stripe-Signature header” with constructEvent(). Without this, anyone who finds the address can send a fake “paid” message.

Fix prompt:

Check my Stripe webhook handler. Make sure it verifies the Stripe-Signature header with the webhook signing secret before doing anything (in a Supabase Edge Function use constructEventAsync). Reject the request if verification fails. The signing secret must be a server-side secret, not in the page.

More detail: Stripe webhook “No signatures found matching the expected signature”.

5. Private files are not public

Your settings file (.env) and your code history folder (.git) should never be downloadable from your live site. Open https://yourdomain.com/.env and https://yourdomain.com/.git/config in a private browser window. You should get a “not found” page, not a file.

6. Source maps are off in production, unless you mean it

Source maps let anyone see your original code in a readable form. Vite leaves them off by default (build.sourcemap is false), but some setups turn them on. If your live site loads files ending in .map, ask your AI tool why.

7. The basic security headers are set

Security headers are settings your site sends to browsers, for example “only use https” and “don't let other sites show my page inside theirs”. They take a few lines in your hosting settings.

More detail: Missing security headers.

8. Sign-up, log-in and payment still work after the fixes

Security changes, especially new database rules, often break sign-up or log-in. After every change, open your live site in a private window, create a test account, log out, log in again, and open the payment page.

More detail: “new row violates row-level security policy” on sign-up.

What an outside check can and can't see

Some of this list can be checked from outside, by anyone. Heedza's free security check reads your home page, up to 6 of your own code files and 4 private files (.env, .env.local, .git/HEAD, .git/config). It flags secret keys it finds there and missing security headers, with a fix to paste into your AI tool. No account needed.

It can't see your database rules. It never logs in, fills in forms or pays. So checks 1, 3, 4 and 8 stay on your list: ask your AI tool, and test by hand.

Let Heedza check this for you. Heedza’s security checks looks for secret keys left in your page code and private files anyone can open. It checks again every time it checks your pages. It never logs in or fills in forms, so it can’t see errors that only show after that.

Made with Lovable, Bolt, Replit, Cursor or v0? Free for 1 site: start free or see prices.

More questions

Is the Supabase anon key in my page a problem?

No. It is meant to be public. What decides who can read and change your data is RLS on every table.

My AI tool's own security scan found nothing. Am I done?

It's a good start. Still go through the list, especially database rules for every table and the hand test of sign-up, log-in and payment on the live site.

Do I need a paid security audit?

If you handle health, bank or legal data, or a client asks for one, yes. For most small apps, this list covers the common mistakes.

Where this comes from