A vibe-coded app is ready for real users when it passes seven checks: each user can only read their own data, no secret keys reach the browser, payments are confirmed by verified webhooks, slow work runs in the background, errors reach you, backups restore, and you own the code and the accounts behind it.
I rebuilt Social Snitch, an app first made with Replit’s AI agent, as a production subscription app, and I take over apps like it through app rescue. This is the list I work through first.
Why an AI-built app needs a second look
By vibe-coded I mean an app built mostly by prompting an AI tool such as Lovable, Bolt, Replit Agent or Cursor. These tools are quick at producing something that works in a demo. The parts a demo never exercises, like a second user or a failed payment, get less attention.
The research backs that up. In Veracode’s 2025 test of more than 100 language models on 80 coding tasks, the generated code introduced a security flaw in 45% of cases[1], and its spring 2026 update found security pass rates still stuck at about 55%[2].
The best-known case involved Lovable. In March 2025 a researcher scanned 1,645 apps from Lovable’s public showcase and found 303 endpoints across 170 of them, about 10%, with row-level security settings that let unauthenticated visitors read or write their database tables[3][4]. It was filed as CVE-2025-48757. Lovable disputes it, saying each customer is responsible for protecting their own app’s data[4]. In April 2025 it added a security scan that runs when you publish[5]. The researcher, Matt Palmer, works at Replit, a Lovable competitor[3].
So a working demo is a starting point. Before real customers sign up, check these seven things.
1. Each user can only read their own data
Most of these tools keep your data in Supabase. Lovable apps run on Lovable Cloud, which is built on Supabase and is on by default, or on a Supabase project you connect yourself[6]. With Supabase, the browser talks to the database directly using a publishable key that anyone can read, so row-level security (RLS) is what decides which rows each request can reach[7].
Check that RLS is on for every table in the public schema, and that each policy ties rows to the signed-in user. The fastest way is the Security Advisor in the Supabase dashboard, which reports a public table without RLS as an error[8]. I wrote a separate guide to the most common Supabase RLS mistakes, with the SQL to find and fix each one.
If your app doesn’t use Supabase, the question is the same: can a signed-in user change an ID in a request and get someone else’s data? Make two test accounts and try it.
2. No secret keys in the browser
Anything shipped to the browser can be read by anyone who opens the developer tools. Publishable keys are designed for that[7]. Secret keys aren’t. Supabase’s secret key, the newer name for the service_role key, bypasses every RLS policy, and Supabase says never to put one in a browser, a shipped app or source control[7]. The same goes for Stripe secret keys and AI provider keys.
Search your repository and the JavaScript your site serves for key prefixes such as sk_live_ (Stripe), sk- (OpenAI), sb_secret_ and service_role (Supabase). If one turns up, rotate it before anything else, then move the code that needs it to the server.
3. Payments are confirmed by webhooks
A checkout page that says thank you doesn’t prove the payment went through. With Stripe, the reliable signal is a webhook: Stripe calls your server when a payment succeeds, a renewal fails or a subscription is cancelled. Check three things in the handler:
- It verifies the
Stripe-Signatureheader on every event, so nobody can fake a "payment succeeded" call[9]. - It can receive the same event twice. Stripe recommends logging the IDs of events you’ve processed and skipping repeats[9].
- It doesn’t depend on order. Stripe doesn’t guarantee events arrive in the order they happened[9], so read the current state from the event or from Stripe instead of assuming an earlier step already ran.
If your server is down, Stripe keeps retrying a failed delivery for up to three days in live mode[9], so a short outage won’t lose payments as long as the handler can catch up. On Social Snitch, Stripe is the source of truth for billing: its webhooks update an account when a subscription starts, renews, fails to charge or is cancelled.
4. Slow work runs in the background
It’s common for a prototype to do everything inside the web request, such as calling an AI model or pulling data from another service. That holds up with a handful of users. Under real traffic those requests time out, and the app looks broken even when nothing has failed.
Move anything that takes more than a few seconds into a background job or a queue, and show the user progress while it runs. On Grubby AI, the long rewriting jobs run in queues so they never block the interface. On Social Snitch, a separate worker server runs the daily data syncs.
5. You hear about errors before your users do
Add error tracking to both the browser and the server, plus alerts for the jobs that matter most, like a failed payment webhook or a background job that stopped. The Social Snitch worker reports its health and emails the admins when a job needs attention, so a stalled sync gets noticed without anyone checking by hand.
6. Backups exist, and you’ve tried restoring one
Find out what backups your database plan includes and how far back they go. Then restore one into a test project, once, before you need it. Back up anything that lives outside the database too, such as uploaded files.
7. You own the code and the accounts
Keep the code in a GitHub repository you control. Lovable, Replit and Bolt can all sync a project to GitHub[10][11][12]. Put the hosting, database, domain, Stripe and email accounts in your company’s name, with your own email as the owner, so you can bring in a developer without asking anyone for access.
Fix it or rebuild it?
If some checks fail, the next question is whether to fix the app where it is or move it to a new codebase. I’ve done both. I kept One Divine Source, a marketplace I took over from an agency, in its existing codebase and have shipped new features every month since. Social Snitch moved to a new Next.js and Supabase codebase.
Run the seven checks
Do they all pass?
Yes
Launch
Run the checks again after big changes
- No
Can it be fixed without rewriting most of it?
No
Rebuild on a clean codebase
Keep the product and the data, and move both
- Yes
Fix it in place
Usually RLS policies, server-side keys, verified webhooks and a job queue
Where to start
If you only have an hour, do the first two checks: open the Security Advisor and search for secret keys. Those are the two most likely to be leaking customer data right now.
Sources
Veracode. (2025, Jul 30). AI-generated code poses major security risks in nearly half of all development tasks, Veracode research reveals. Retrieved from https://www.veracode.com/press-release/ai-generated-code-poses-major-security-risks-in-nearly-half-of-all-development-tasks-veracode-research-reveals/
Veracode. (2026, Mar 24). Spring 2026 GenAI code security update. Retrieved from https://www.veracode.com/blog/spring-2026-genai-code-security/
Palmer, M. (2025, May 29). Statement on CVE-2025-48757 and the technical advisory CVE-2025-48757. Retrieved from https://mattpalmer.io/posts/statement-on-CVE-2025-48757/ and https://mattpalmer.io/posts/CVE-2025-48757/
NIST National Vulnerability Database. (2025, May 30). CVE-2025-48757. Retrieved from https://nvd.nist.gov/vuln/detail/CVE-2025-48757
Lovable. (2025, Apr 25). Changelog: Lovable 2.0. Retrieved from https://docs.lovable.dev/changelog
Lovable Documentation. Supabase integration. Retrieved from https://docs.lovable.dev/integrations/supabase
Supabase Documentation. Understanding API keys. Retrieved from https://supabase.com/docs/guides/api/api-keys
Supabase Documentation. Database advisors: RLS disabled in public. Retrieved from https://supabase.com/docs/guides/database/database-linter?lint=0013_rls_disabled_in_public
Stripe Documentation. Receive Stripe events in your webhook endpoint. Retrieved from https://docs.stripe.com/webhooks
Lovable Documentation. GitHub integration. Retrieved from https://docs.lovable.dev/integrations/github
Replit Documentation. Git interface. Retrieved from https://docs.replit.com/features/workspace-tools/git-interface
Bolt Support. Git integration. Retrieved from https://support.bolt.new/integrations/git
Written by
Founder and engineer at Blue Nebula, a one-person studio in Daly City, CA, that builds web apps, Shopify stores and AI features. Top Rated Plus on Upwork with 3,700+ hours of client work.
More about me