Security checklist for apps built with Lovable, Bolt, Cursor and v0

Twelve checks to run before real users and real data arrive, and which of them no outside scanner can do for you.

By , Founder, SproutPublished 10 min read

Key takeaways

  • The most common serious flaw in AI-built apps is not clever hacking but missing access control: a database table or API route that answers anyone who asks.
  • A Supabase anon key in the browser is normal; a Supabase service_role key, a Stripe secret key or an OpenAI key in the browser is an incident that needs rotating today.
  • Row Level Security must be enabled and written for every Supabase table, because the anon key can reach exactly what those policies allow.
  • An external scan can find exposed keys and missing headers, but only you can confirm that one user cannot read another user's records.

To secure an app built with Lovable, Bolt, Cursor or v0, check four things before launch: no secret keys in the browser bundle, database access rules (Supabase RLS or Firebase rules) on every table, authentication on every API route, and basic security headers. Most real exposures in AI-built apps come from the first three.

AI coding tools are good at producing something that works on the happy path. Security failures live off the happy path: the request nobody in the demo made, the user who changes an ID in the URL, the key that was convenient to paste into the frontend. The tool did what you asked. Nobody asked it to say no.

This checklist is ordered by how much damage each item does when it goes wrong, not by how hard it is to fix. Most items take under an hour.

1. Secrets shipped to the browser

Anything in your frontend code, including environment variables bundled at build time, is readable by every visitor. Open DevTools, go to Sources, and search the JavaScript for “sk_”, “sk-”, “AKIA”, “service_role” and “PRIVATE KEY”. If an AI tool wired a third-party API straight from a React component, the key is almost certainly there.

Some keys are public by design. A Supabase anon or publishable key and a Firebase web config are meant to ship to the browser. Google Maps and Firebase browser keys are fine too, provided they are restricted to your domain and the APIs you use. Everything else is not.

KeySafe in the browser?If it is exposed
Supabase anon / publishable keyYes, if RLS is on for every tableNothing, by itself. Check RLS (item 2).
Supabase service_role / secret keyNeverRotate now. It bypasses every RLS policy.
Stripe secret key (sk_live_, sk_test_)NeverRotate now. A live key can issue charges and read payment data.
OpenAI or Anthropic API keyNeverRotate now, then proxy AI calls through your backend.
AWS access keyNeverRotate the key pair and review what it could reach.
Google / Firebase browser keyYes, if restrictedRestrict it to your domains and the APIs you use.

Rotating means issuing a new key and revoking the old one. Deleting the key from your code is not enough: the old bundle and your git history still contain it.

2. Supabase Row Level Security on every table

Supabase's own documentation is direct about this: the publishable key only reaches what Row Level Security allows, so RLS should be enabled on every table before you deploy. A table with RLS disabled is readable and writable by anyone holding your public key, which is everyone.

In the Supabase dashboard, open each table and confirm RLS is enabled. Then read the policies. A policy of “true” for select is the same as no policy. The pattern you usually want is that a row is visible only when its “user_id” matches “auth.uid()”. The Supabase RLS guide has worked examples.

Then test it the way an attacker would. Sign in as user A, copy a request from the Network tab that fetches user A's data, and replay it with user B's session, or with no session at all. If you get data back, the policy is wrong.

3. Firebase security rules

Firebase has the same failure in a different shape. Rules of “allow read, write: if true;” are fine for an afternoon of prototyping and dangerous everywhere else. Google's own page on insecure rules says never to use that rule set in production, because anyone who guesses your project ID can read, change or delete your data. Your project ID is in your web config, so assume it is known.

Write rules that check “request.auth.uid” against the owner of each document, and use the Rules Playground in the Firebase console to try reads as a signed-out user and as a different user.

4. Authentication on every API route

AI tools often protect the page and forget the endpoint behind it. The dashboard redirects signed-out visitors to the login screen, but “/api/orders” happily returns every order to anyone who calls it directly. Hiding a button is not access control.

Go through every server route, edge function and serverless function and confirm two things: it rejects requests with no valid session, and it only returns records the signed-in user owns. That second check is what OWASP calls broken object level authorization, and Broken Access Control is ranked first in the OWASP Top 10:2025.

The quick test: find a request that includes a record ID, such as “/api/invoices/1042”, and change it to “1041”. You should get a 403 or a 404. Guessable sequential IDs make this attack easier, so prefer UUIDs, but UUIDs do not replace the ownership check.

5. Admin routes and internal tools

Search your codebase for “admin”, “internal”, “debug” and “seed”. AI-generated apps often contain an admin page protected only by not being linked anywhere, or a role check done in the frontend. Both fall to anyone who reads your JavaScript. Admin checks belong on the server, against a role stored in your database, not in a flag the client sends.

6. Security headers

Headers are cheap defence in depth. They will not fix a broken policy, but they limit the damage of the bugs you have not found yet. The four worth setting on day one, all explained in the OWASP HTTP headers cheat sheet:

  • Content-Security-Policy. Restricts where scripts can load from, so one injected script cannot quietly run with full access to the page. Start in report-only mode; the MDN CSP guide explains the directives.
  • Strict-Transport-Security. Tells browsers to use HTTPS only, so a first visit cannot be downgraded to plain HTTP. See MDN on HSTS.
  • X-Frame-Options or CSP frame-ancestors. Stops other sites embedding yours in an iframe to trick users into clicking (clickjacking).
  • X-Content-Type-Options: nosniff. Stops browsers guessing file types, which can turn an uploaded file into executable script.

7 to 12. The rest of the pre-launch list

  1. 7. Rate limit anything that costs money or guesses passwords

    Login, signup, password reset, and every endpoint that calls a paid AI model. Without a limit, one script can try thousands of passwords or run up your OpenAI bill overnight.

  2. 8. Keep secrets out of URLs

    Tokens and API keys in query strings end up in server logs, browser history and Referer headers. Send them in a header or the request body.

  3. 9. Load everything over HTTPS

    A single “http://” request from an HTTPS page can expose whatever it carries. Check the Network tab for any request that is not HTTPS.

  4. 10. Do not leak errors

    Stack traces, SQL errors and file paths in API responses or the browser console tell an attacker what you run and where it breaks. Return a generic message and log the detail server-side.

  5. 11. Lock down CORS

    An API that echoes back whatever Origin it is sent, with credentials allowed, lets any website make signed-in requests from your users' browsers and read the answers. List your own domains explicitly instead of reflecting the request.

  6. 12. Audit dependencies

    Run npm audit and fix high and critical advisories. AI tools pin whatever version they last saw, which is sometimes one with a known vulnerability.

What an outside scan can and cannot see

Some of this list can be checked from outside your app, by loading it the way a visitor does. Truewick's free health check does that in a real browser. On the security side it searches the page HTML, browser storage and your same-origin JavaScript bundles for high-confidence key patterns: Stripe secret keys, OpenAI and Anthropic keys, AWS access keys, GitHub, Slack and SendGrid tokens, private key blocks, and Supabase service_role keys (it decodes the JWT and only flags the service role, so a normal anon key is not reported as a leak). Google API keys are flagged as needing restriction rather than as leaks.

It also reports missing Content-Security-Policy, HSTS, clickjacking protection and nosniff headers, requests sent over plain HTTP from an HTTPS page, tokens or keys passed in URL query strings, and API calls that use guessable sequential IDs, which it flags as a prompt to run the ownership test in item 4 by hand. Alongside that it runs Lighthouse for performance, accessibility, best practices and SEO, an accessibility check with axe-core, a broken-link and console-error pass, and screenshots at phone, tablet and desktop widths.

Without an account, the scan covers one page and shows the scores, the top general findings, and how many security issues it found and how severe they are. The details of security findings appear only after you sign up. That is deliberate: anyone can type anyone's URL into a public form, and listing another company's exposed keys to a stranger would make the scan a reconnaissance tool.

When to get help

If the scan or your own check turns up a live secret key, rotate it first and investigate second. If it turns up a table with RLS off and real user data in it, assume the data has been read: check your provider's logs and take advice on whether you need to notify users.

If the list is longer than you can work through before launch, a code audit by someone who did not write the app is the fastest way to find the access-control gaps. Sprout, the studio that builds Truewick, runs fixed-price audits and fixes for AI-built apps. Any competent engineer who reads the code and tests as a second user will find the same class of problems.

Frequently asked questions

Is it safe to expose the Supabase anon key?
Yes, the anon or publishable key is designed to be public, but only if Row Level Security is enabled on every table with policies that limit each user to their own rows. Without RLS the anon key can read and write the whole table. The service_role or secret key must never be exposed.
Are apps built with Lovable or Bolt secure?
They can be, but the tools optimise for a working demo, not for refusing bad requests. The common gaps are missing database access rules, API routes with no ownership check, and secret keys placed in frontend code. Each is fixable, and each needs to be checked deliberately before real users arrive.
How do I check if my API key is exposed in my website?
Open your site, open the browser DevTools, and search the loaded JavaScript files under Sources for prefixes such as sk_live_, sk-, AKIA and service_role. Anything you can find there, every visitor can find. The free Truewick scan runs the same search automatically across the page, browser storage and same-origin bundles.
What should I do if a secret key was in my frontend code?
Rotate it immediately: create a new key, move it to your server, and revoke the old one. Removing it from the code is not enough, because old deployments, caches and your git history still contain it. Then check the provider's usage logs for activity you do not recognise.
What security headers does a web app need?
At minimum Content-Security-Policy, Strict-Transport-Security, X-Frame-Options (or CSP frame-ancestors) and X-Content-Type-Options: nosniff. Most hosting platforms let you set them in a config file in a few lines. Start CSP in report-only mode so it does not break the app while you tune it.
Can a website scanner find broken access control?
Not reliably from the outside. A scanner can spot hints, such as guessable sequential IDs in API calls, but proving that one user cannot read another user's data needs two accounts and a request replayed between them, or someone reading the server code. Treat a clean scan as necessary, not sufficient.

Sources

Written by

Usman founded Sprout, the product studio that builds Truewick, and leads its engineering as CTO. Usman is also a founding engineer at Kollegio AI, a Stanford-backed college counseling platform serving more than 300,000 students, and studied Computer Science at LUMS.