Your Lovable app looks finished. The screens work, the flows make sense, and you're ready to put it in front of paying customers.
The gap between that and production is almost entirely invisible from the front end. It sits in the database rules, the server functions, and the payment handling, and it's where AI builders consistently leave gaps because nobody explicitly asked them not to.
The scale of this isn't hypothetical. In March 2025, security researcher Matt Palmer disclosed CVE-2025-48757, an exposure in Lovable-generated apps that affected more than 170 production applications, all traced to missing database access rules. A Q1 2026 audit of roughly 5,600 AI-generated apps by Escape.tech reported that the large majority contained at least one critical vulnerability.
The good news: these are known, fixable problems with a known order to fix them. Work through this list before you launch.
Part 1: The database (do this first)
1. Row-level security is on for every table
This is the big one, and the cause of the CVE above. A Lovable app talks to your Supabase database directly from the browser using a public key. That key is meant to be public. The only thing standing between it and your data is row-level security (RLS): rules that restrict each user to their own rows.
An important detail many people miss: Supabase enables RLS automatically only when you create a table through the dashboard's Table Editor. Tables created another way, including by an AI agent writing migrations, can arrive with it switched off.
How to check: open your Supabase dashboard and look at the table list. Supabase itself flags tables without RLS. Any table holding user data with RLS off is readable by anyone who has your public key, which is anyone who opens your app.
2. Your policies aren't secretly wide open
RLS being "enabled" isn't the finish line. A policy that effectively permits everything protects nothing. Two patterns to look for:
- A policy that always evaluates to true, which allows every row to every caller.
- A read policy with no matching restriction on writes, which lets users modify records they should only be able to view.
How to check: for each table, ask who should be able to read a row, and who should be able to change it. Then verify the policy expresses exactly that, by signing in as two different test users and confirming neither can see the other's data.
3. Storage buckets are protected too
File storage has its own access controls, separate from your tables. If your app accepts uploads, profile photos, documents, anything, those files need their own rules. A public bucket means every uploaded file is reachable by URL.
Part 2: Secrets
4. No private keys reach the browser
Some keys are meant to be public: the Supabase anon key, the Stripe publishable key. Others must never leave your server: the Supabase service-role key, your Stripe secret key, any AI provider key.
The service-role key deserves special mention because it bypasses RLS entirely. Exposed, it hands over full access to your database regardless of how good your policies are.
How to check: open your live app, open the browser's developer tools, and search the loaded JavaScript for service_role, sk_live, and sk-. Anything you find there is public. Rotate it immediately, then move the operation that needed it into an edge function.
5. Your chat history isn't leaking secrets
A subtler one. If you pasted an API key into the Lovable chat while building, it may persist in the project history even after the code itself was fixed. Rotate any key that has ever appeared in a prompt.
Part 3: Server functions
6. Every edge function verifies its caller
Supabase edge functions are your server-side code: payments, AI calls, admin actions. AI-generated functions often do exactly what they're asked without checking who's asking. Anyone who finds the URL can call them directly, bypassing your interface entirely.
How to check: list every edge function. For each, confirm it verifies the user's session and checks that this particular user is allowed to perform this action on this record.
7. Admin areas are protected on the server
Hiding the admin link from non-admins is a user interface decision, not security. If /admin loads for an ordinary signed-in user who types the URL, it isn't protected.
How to check: sign in as a normal test user and visit every admin URL directly.
Part 4: Money and accounts
8. Stripe access comes from webhooks, not the success page
If your app grants paid access when someone lands on a "payment successful" page, two things will happen: some users will reach that page without paying, and some who paid will close the tab too early and get nothing.
Access should be granted by a Stripe webhook, with the signature verified so you know the request genuinely came from Stripe, and written so the same event arriving twice doesn't grant or charge twice.
9. The full account lifecycle works on a real phone
Sign-up, email verification, login, password reset, and logout, tested end to end on an actual phone as well as a desktop browser. Password reset links that open the wrong page are among the most common bugs in AI-built apps, and you only discover them when a real customer is locked out.
Part 5: Before you flip the switch
10. Separate environments
You need somewhere to test that isn't your live app, with its own database. Otherwise every prompt you run is an experiment on your customers.
11. Backups you've actually restored
Confirm backups are running, then restore one into a test database. A backup nobody has restored is a hope, not a plan.
12. You'd hear about a crash before your users tell you
Add error monitoring. Without it, the first report of a broken checkout is an email from a frustrated customer, days later.
How to read your score
- 11–12: Launch. Keep watching your error monitor.
- 8–10: Fix the gaps before spending anything on traffic. Items 1 to 5 come first, always.
- Below 8: Don't launch yet. These issues compound, and they get much more expensive once real customers and real data are involved.
When prompting stops working
AI builders are excellent at generating features and much weaker at finding problems that span several systems at once: the database, the payment provider, and the front end together. A practical rule: if the same bug has survived three rounds of prompting, it's structural, and more prompting won't fix it.
That's the point where a few weeks of engineering is cheaper than another month of credits.
If you'd rather someone else did this
That's exactly what our Lovable app rescue service is for. We audit what the AI built, fix the security, payment, and data issues, and hand the app back in your own GitHub and Supabase accounts, with one fixed price agreed after the audit.
Built with something else? We have the same process for Bolt and Replit, and a general AI-built app rescue page covering v0, Cursor, and the rest.
Either way, send us the project link and we'll give you an honest read on where it stands.
