AI-Built App Production Checklist: Lovable, Bolt, Cursor
54 checks across 9 areas to take a Lovable, Bolt or Cursor app to production in 2026: auth, RLS, secrets, payments, infra, privacy and handoff.
An AI-built app is ready for production when it passes the 54 checks below, grouped into 9 areas. Start with the 20 checks in auth, data and secrets, because that’s where documented failures cluster. Escape’s scan of 5,600 public vibe-coded apps found more than 2,000 vulnerabilities and 400+ exposed secrets, and most of them traced back to missing or permissive Row Level Security.
Every item has a one-line “how to check,” and most take under ten minutes. They assume the common 2026 stack: a Lovable, Bolt, v0 or Cursor frontend on Supabase (Postgres, Auth, Storage, Edge Functions), deployed to Vercel, Netlify or the builder’s own hosting, with Stripe for payments. If you’re on Firebase, the same ideas map onto Security Rules.
TL;DR
- Do sections 1–3 before you have real users. They cover the failures that leak data.
- Do section 4 before you take real money. Unverified webhooks and duplicate events cause most payment bugs.
- Sections 5–7 decide whether you find out about problems before your users do.
- Sections 8–9 matter the moment someone else depends on the app: a customer, an investor, or the engineer you hire next.
- Don’t trust a green “security scan” alone. Lovable’s own docs say its scanner cannot guarantee complete security.
Numbering runs across sections, so you can tell a co-founder “we fail 9 and 31.”
1. Authentication
Broken access control is number one on the OWASP Top 10:2025, and in AI-built apps it usually starts with auth checks that only exist in the UI.
- Every protected page also checks auth on the server. How to check: log out, then call the API or Supabase query behind the page directly from the browser console or with
curl. It should fail. - Signup can’t be used to join someone else’s workspace or private app. How to check: try registering with an invite link, an org ID or an app ID you weren’t given. Wiz found exactly this bypass in Base44.
- Email confirmation is on, and unverified users can’t reach paid or private features. How to check: sign up with an address you control, don’t confirm it, and try the app.
- Password reset and magic links expire and work only once. How to check: request two reset emails and use the first link after the second one.
- Auth email goes through your own SMTP provider. How to check: look in Supabase Auth settings. The built-in sender is limited to 2 emails per hour, so signups break the first day you get traffic.
- Roles and admin flags aren’t read from user-editable metadata. How to check: search policies and code for
user_metadataorraw_user_meta_data. Supabase notes users can update that field themselves, so useapp_metadataor a roles table.
2. Data and Row Level Security
- RLS is enabled on every table in an exposed schema. How to check: run the Supabase Security Advisor or
supabase db advisors. Lint0013_rls_disabled_in_publicmust be clean. - No table is readable with just the anon key unless it’s meant to be public. How to check: copy the anon key from your site’s JavaScript bundle and query each table with it, logged out. This is how CVE-2025-48757 was found in 170 Lovable apps.
- Policies scope rows to the owner or the org, not just “authenticated.” How to check: search for policies with
using (true)orauth.role() = 'authenticated'. Then log in as user A and request user B’s rows by ID. - Insert and update policies have
with check, not justusing. How to check: as user A, try to insert a row with user B’suser_id, or update your own row to change its owner. - Policies are tested in code, not just eyeballed. How to check: you have a
supabase test dbsuite (or similar) covering select, insert, update and delete for anon and authenticated roles. Supabase’s docs recommend exactly this. - Storage buckets have policies too. How to check: open a private file’s URL in a logged-out browser. Signed URLs should expire. Public buckets should hold only public assets.
- Database functions and views don’t bypass RLS by accident. How to check: list
security definerfunctions and views. Each one needs a reason, and an explicit permission check inside. - Schema changes live in migrations, not dashboard clicks. How to check:
supabase/migrationsexists in the repo and recreates the production schema on a fresh project.
3. Secrets
- No secret keys ship to the browser. How to check: search the built JavaScript for
sk_live,sk-,service_roleand your provider prefixes. Supabase warns the service role key bypasses every RLS policy. - The repo’s history is clean. How to check: run gitleaks with
gitleaks git -vover the full history, not just the latest commit. - Third-party API calls (OpenAI, Anthropic, Resend, Twilio) run server-side. How to check: open the browser network tab while you use each feature. Requests to those vendors’ domains shouldn’t come from the browser.
- Secrets are marked sensitive in your host. How to check: in Vercel, confirm each secret uses the sensitive flag. In April 2026, variables without it were exposed in a platform incident.
- You have a written list of every secret and how to rotate it. How to check: the list exists, and someone has rotated at least one key from it without downtime.
- Anything ever pasted into an AI chat has been rotated. How to check: compare your secrets list against what’s been in Lovable, Bolt or Cursor prompts. When in doubt, rotate.
4. Payments
- Stripe webhooks verify the signature. How to check: send a fake POST to your webhook URL. It must be rejected. Stripe says to always verify that events came from Stripe.
- Webhook handling is idempotent. How to check: resend the same event from the Stripe dashboard. Stripe retries for up to three days and can deliver duplicates, so a second delivery shouldn’t grant access twice or send two emails.
- Your code doesn’t assume webhook order. How to check: look for logic that expects
invoice.paidaftercustomer.subscription.created. Stripe doesn’t guarantee order. - Access is granted by the server from Stripe’s data, never from a success-page redirect. How to check: visit your success URL directly without paying.
- Prices and plan limits come from the server. How to check: change the price or plan ID in the checkout request from the browser. The server must ignore it.
- Usage-based costs have hard caps. How to check: find the per-user and global limits on LLM calls, SMS and email. OWASP lists unbounded consumption among the top LLM risks, and a single abusive account can run up a provider bill in an afternoon.
5. Infrastructure
- Development and production use separate databases. How to check: your local and preview env vars point at a different Supabase project from prod. Replit added this separation after its agent deleted a production database.
- AI agents can’t touch production. How to check: list which tools and MCP servers hold prod credentials. The answer should be none.
- Backups exist and have been restored at least once. How to check: confirm your plan. Supabase’s free tier has no automatic daily backups. Then restore one into a scratch project.
- Point-in-time recovery is on if losing a day of data would hurt. How to check: look in Supabase project settings for the PITR add-on.
- Deploys come from Git, and you can roll back in one step. How to check: redeploy the previous commit and time how long it takes.
- The custom domain has HTTPS, and DNS is in an account you control. How to check: look up your registrar login. If it belongs to a freelancer, move it.
- Rate limits protect login, signup and expensive endpoints. How to check: fire 100 login attempts in a minute with a script and see whether anything slows you down.
- Dependencies have no known critical vulnerabilities. How to check: run
npm audit --omit=devand check your platform’s dependency scan.
6. Observability
- Frontend and backend errors go to an error tracker. How to check: throw a test error in production and confirm it shows up in Sentry (or similar) with a stack trace.
- Someone gets alerted when the app is down. How to check: an uptime monitor pings the app and a key API route, and the alert goes to a phone, not an unread inbox.
- Server logs are kept and searchable for at least 7 days. How to check: find yesterday’s failed request in your logs within two minutes.
- Logs don’t contain secrets or personal data. How to check: search logs for
Authorization,passwordand email addresses. - Key business events are tracked. How to check: you can answer “how many signups and payments failed yesterday” without opening the database.
7. Performance
- Core Web Vitals pass at the 75th percentile. How to check: PageSpeed Insights or your analytics. The “good” thresholds are LCP within 2.5s, INP of 200ms or less, CLS of 0.1 or less.
- Columns used in RLS policies and filters are indexed. How to check: run the Supabase Performance Advisor, and look for sequential scans in
explain analyzeon your busiest queries. - Policies call
auth.uid()once per query, not once per row. How to check: policies use(select auth.uid()), which lets Postgres cache the result. - List pages paginate. How to check: seed 10,000 rows in staging and load every list view.
- There are no N+1 query loops in the frontend. How to check: open the network tab on a list page. One request per row is a bug.
8. Legal and privacy
- A privacy policy matches what the app actually collects. How to check: list every third party that receives user data (analytics, LLM provider, email, payments) and confirm each appears in the policy.
- You have DPAs with processors that handle personal data. How to check: Supabase, your host, your email provider and your LLM provider each have a signed or accepted data processing agreement.
- Users can delete their account and data. How to check: delete a test account and confirm its rows, files and Stripe customer are removed or anonymized.
- You know how you’d handle a breach. How to check: a one-page plan names who decides and who notifies. Under GDPR you have 72 hours to notify the regulator.
- Cookie consent matches your trackers. How to check: load the site in a fresh browser in an EU region and confirm no analytics cookies are set before consent.
- AI features are disclosed where the law requires it. How to check: if EU users chat with an AI or see AI-generated content, review EU AI Act Article 50, whose transparency obligations are set to apply from 2 August 2026.
9. Handoff
- The code is in a Git repo you own. How to check: the GitHub organization is yours, not the builder’s or a contractor’s.
- A new engineer can run the app locally from the README. How to check: have someone who hasn’t seen it try. Time it.
- There’s a list of every account the app depends on, with owners. How to check: domain, DNS, hosting, Supabase, Stripe, email, LLM providers, app stores. Each has a named owner and 2FA turned on.
- The critical paths have automated tests. How to check: signup, login, payment and the main user action each have at least one end-to-end test that runs in CI.
How to use this checklist
Go in order. A failure in sections 1–3 means stop and fix it before anything else, because it’s the kind of failure that leaks data. Failures in sections 4–7 can usually be scheduled into the next couple of weeks. Sections 8 and 9 are the ones investors, enterprise buyers and your next engineer will ask about.
A few things this list won’t catch:
- Logic bugs specific to your product. An inverted condition in an auth helper passes every item above. The Register described one such bug in a Lovable-built app that exposed 18,697 user records.
- Data model problems. If the same customer lives in three tables, no policy will save you. That’s a refactor-or-rebuild question, which we cover in what it costs to fix a vibe-coded app.
- Prompt injection in AI features. If your app passes user input to an LLM that can call tools or read data, read the OWASP Top 10 for LLM Applications. Prompt injection is number one.
Scanners from Lovable, Supabase and others are worth running, and they’re getting better. They’re a floor, not a sign-off. Veracode found that 45% of AI-generated code introduced a security flaw in its tests, and most of those flaws look like working code.
Want a second pair of eyes?
If you’ve worked through the list and you’re still unsure about sections 1–4, that’s what our AI-App Rescue Audit is for. It’s $1,490 fixed and delivered in 72 hours. A senior engineer goes through these areas on your actual code and database, and you get a prioritized fix list. If you want us to do the fixes, the fee is credited toward a Stabilization Sprint (from $7,500 for two weeks).
Planning to add an AI feature rather than fix one? The AI Feature Sprint builds it to this standard from day one. Or book a call and tell us which items you failed.