Why this pass matters
A working demo proves the idea. It proves nothing about production. AI-generated code fails in consistent, well-documented ways, and the numbers are not improving: Veracode’s GenAI Code Security Report found that 45% of AI-generated code introduces an OWASP Top-10 vulnerability, and the security pass rate has stalled around 56% through spring 2026 despite steadily better models.
Vibe-coded apps specifically are worse off, because nobody has read the code. In 2025, Escape.tech scanned more than 1,400 vibe-coded apps and found over 2,000 vulnerabilities, including 400+ exposed secrets and leaked personal data. Lovable itself has a documented entry in that record: CVE-2025-48757 covered 170 live Lovable apps exposing names, emails and financial data through missing row-level security.
None of that makes Lovable a bad tool. It makes launch a separate discipline — the same one we work through in a vibe coding security audit. Work down this list in order. The first three items are where the real damage happens; everything after them is what separates an app that launches from an app that survives launching.
Supabase row-level security
Your Lovable frontend ships with the Supabase anon key. That is by design — but it means every table without row-level security is a public API. Anyone who opens your site’s source can query those tables directly, with no login, using nothing but that key and the standard Supabase client. This is the exact mechanism behind CVE-2025-48757, and it is the single most common hole in shipped Lovable apps.
Checking takes minutes. Open the Supabase dashboard and run the Security Advisor — it flags every table without RLS. Enabling RLS is not enough on its own: a table with RLS enabled and no policies blocks everything, and a table with a sloppy policy allows everything. Write policies per table, default to deny, and grant only what each role genuinely needs.
RLS enabled on every table
Including the ones Lovable created early and you forgot about. There are no internal tables — the anon key reaches them all.
Policies tested as the wrong user
Query the API as an anonymous visitor and as a different logged-in user. If you can read another user’s rows, so can everyone.
Storage buckets locked down
Supabase Storage has its own policies. Private uploads in a public bucket are public files with guessable URLs.
Service-role key nowhere in the client
It bypasses RLS entirely. It belongs in edge functions and nowhere else — search your codebase to be sure.
Secrets, server-side
Everything in your frontend bundle is published. Open your live site, view source, and search the JavaScript for key prefixes — sk_ for Stripe, AIza for Google, or the name of any API you asked Lovable to integrate. AI tools routinely paste secret keys into client code because that is the shortest path to a working demo, and it was one of the most common findings in the Escape.tech scan of vibe-coded apps — 400+ exposed secrets across 1,400+ apps.
The fix has two parts, and most people skip the second. First, move every call that needs a secret into a Supabase edge function and store the key in the function’s secrets, not in code. Second, rotate every key that ever shipped to the browser. A key that was public for a week is burned — moving it server-side does not un-publish it.
Auth on the server, not in the interface
Lovable’s default failure mode is interface auth: the admin page is hidden unless you are an admin, but the endpoint behind it answers to anyone. Hiding a button is not access control. The request it makes still exists, and anyone can send it with curl and a copied session token.
Every API route and edge function must verify the caller’s session itself — validate the JWT, load the user’s role from the database, and reject anything unauthorized. Roles read from client state are decoration. The test is blunt: log in as a normal user, then call each admin or write endpoint directly from the terminal. Anything that answers is a finding. This pairs with RLS — the database policies are the second lock when a route check is missed.
Custom domain and DNS
A lovable.app subdomain is fine for a demo and wrong for a launch. Connect a custom domain and give the DNS ten unglamorous minutes, because half-done DNS shows up as broken magic links and login redirects to the old domain — failures your users hit before you do.
Apex and www both resolve
One should 301 to the other. Pick a canonical form and stay with it — search engines treat them as different sites.
Auth redirect URLs updated
Supabase auth still pointing at the old preview domain breaks email confirmation and password resets silently.
SSL valid on the final domain
Load the site fresh in a private window after DNS settles. A certificate warning on day one costs more trust than any bug.
SPF and DKIM if you send email
Transactional email from an unauthenticated domain lands in spam. Set the DNS records your email provider specifies.
Stripe webhooks: verify, then trust
The demo pattern for payments is trusting the success redirect: the user lands on /success, so mark them paid. Users can visit that URL without paying. Fulfillment must come from Stripe webhook events, and your webhook handler must verify Stripe’s signature with the webhook signing secret — otherwise anyone who finds the endpoint can POST a fake payment event and get whatever you sell for free.
While you are in there: confirm you are on live keys, not test keys that quietly accept nothing. Run the full flow in test mode including a declined card. And make the handler idempotent — Stripe retries webhooks, and a retry should not fulfill an order twice.
Error monitoring and backups
After launch, the question is not whether something breaks but whether you find out from a tool or from a customer. Add error monitoring — Sentry’s free tier is enough to start — plus an uptime check on the domain. Ten minutes of setup buys you the difference between fixing a bug at 9am and reading about it in a refund request.
Then backups. Know what your Supabase plan actually includes, how far back it goes, and whether point-in-time recovery is on if your data matters. And restore one backup, once, before launch. A backup you have never restored is a hope, not a backup.
Analytics and Search Console
Wire analytics before launch, not after — day-one numbers do not exist retroactively. GA4 or a privacy-friendly alternative both work; what matters is that page views and your one or two key conversion events are firing before the first real visitor arrives.
Verify the domain in Google Search Console, submit a sitemap, and check that your public pages are indexable. Lovable’s default page titles and descriptions are generic — rewrite them on every public page. This is also where DNS mistakes surface: if Search Console sees a redirect loop, so does Google.
The performance pass
Run Lighthouse against the live site on a mobile profile and read what it says. Lovable apps are rarely slow because of the framework — they are slow because of what the generated code does with data and images.
- Compress and resize images — AI-generated pages routinely ship multi-megabyte hero images at full resolution.
- Move filtering into the query. Fetching a whole table and filtering it in the browser works with ten rows and dies with ten thousand.
- Add database indexes on columns you filter or sort by — Supabase’s advisor will suggest the obvious ones.
- Cache what does not change per user instead of refetching it on every render.
Security headers and CSRF
The cheapest security wins on this list. Run your domain through a header checker and add what is missing: a Content-Security-Policy, Strict-Transport-Security, X-Content-Type-Options, and frame-ancestors so your login page cannot be embedded in someone else’s site. Generated apps ship without these almost universally.
If any authentication runs on cookies, state-changing endpoints need CSRF protection — a request forged from another site should fail, and in most generated codebases it will not. Finish with rate limiting on login, signup and anything that sends email, or the first bored script will run your password reset flow all night.
If you are stuck in a bug loop
The pattern is unmistakable: every prompt fixes one thing and breaks another, and the app is somehow getting worse. This is not bad luck. Each round of fixes layers duplicated, contradictory code into the project, and past a certain depth the model is patching its own patches.
Stop prompting. Use Lovable’s version history or GitHub sync to revert to the last state that genuinely worked, then move in single, small changes — one bug, one prompt, verify, commit. If the base itself is tangled and even reverts do not help, that is the point where a human engineer untangles it once so prompting works again. It is the most common job we take on when we fix Lovable apps, and it is usually days of work, not weeks.
And if you would rather have every item on this page checked for you: send the URL and a senior engineer runs the full pass by hand, with written findings in 48 hours, through the free technical audit. No call, and the findings are yours either way.