Back to BlogCode Rescue & Fixes

How to Make a Lovable, Bolt or Cursor App Production-Ready

Rupak Amin

Founder & Lead Engineer, RAITHub

13 min read

A Lovable, Bolt or Cursor app is production-ready when it keeps secrets on the server, checks authorization on every record, validates input, has tests on its critical paths, logs its errors, and deploys the same way every time. Apps generated this way often work in the preview and miss several of these. The checklist below finds each gap in about 10 minutes.

This guide is for founders who built a working app with an AI tool and now need it to survive real users, real data and real bills. It does not argue against AI coding tools. They are a fast way to get to a working product. The point is that "working" and "safe to put customers on" are different tests, and the second one has to be run on purpose.

Why does a vibe-coded app work in the preview and break in production?

Because the preview is one friendly user on test data, and production is many users, some of them hostile, on real data with a different configuration. AI tools are very good at the first case and do not, by default, test the second.

The research points the same way. Veracode's 2025 GenAI Code Security Report tested code from more than 100 large language models and found that 45% of the samples introduced an OWASP Top 10 vulnerability; it also found that newer and larger models were not more secure, even as they got better at producing code that runs. A Stanford user study, "Do Users Write More Insecure Code with AI Assistants?" (Perry et al., ACM CCS 2023), found that participants with an AI assistant wrote less secure code than those without one, and were more likely to believe their code was secure.

That second finding matters most. The risk is not only the bug; it is the confidence that there is no bug.

The clearest real-world example involved a popular app builder. In the disclosure of CVE-2025-48757, the researcher reports a scan that found 303 vulnerable endpoints across 170 of 1,645 Lovable-built projects analysed, about 10.3%. The root cause, per the advisory, was insufficient row-level security policies on database requests made directly from the browser with the public key. Lovable added a security scan in April 2025, according to the same timeline, but a project's policies are still the owner's responsibility.

What are the 10 production gaps, and how do you check each one?

Work down this table in order. Each check takes about 10 minutes for someone comfortable with a browser's developer tools; each fix ranges from an hour to a few days depending on the size of the app.

GapHow to check in 10 minutesFix
1. Secrets in client codeOpen the live site, then the browser's developer tools, and search the loaded JavaScript for "sk_", "secret", "service_role" and your provider names. Search the repository for secret values in variables prefixed NEXT_PUBLIC_ or VITE_, which are shipped to the browserMove every privileged call to a server route. Rotate every key that was ever exposed; a leaked key stays leaked after you delete it
2. Missing row-level security or authorization checks (IDOR)Log in as user A and copy the ID of one of A's records. Log in as user B in a private window and request that ID through the app or API. On Supabase, also check whether every table has RLS enabledEnable RLS on every table with policies scoped to the signed-in user; check ownership on the server for every read and write; add a test that tries the attack
3. No input validationSubmit forms with empty fields, 10,000 characters, negative numbers and HTML. Call the API directly with an extra field such as "role": "admin"Validate every request on the server with a schema, and accept only the fields each endpoint expects
4. No testsRun the test command. Count the tests, and check whether any cover sign-up, login and paymentWrite end-to-end tests for the three to five journeys that make money or hold data first, then run them in CI on every change
5. No error handling or loggingBreak something deliberately: go offline mid-action, submit bad data, stop a third-party key. Does the user see a clear message, and does the error reach anywhere you would notice?Error boundaries and friendly error pages, structured server logs, error tracking with alerts to a person
6. Config drift between preview and productionList the environment variable names in preview and production side by side. Check which database production actually points atOne validated environment schema, and a build that fails when a required production variable is missing
7. Dependency and peer conflicts at deployIn a clean checkout, run the exact install command your host runs, not the one that works locallyResolve the conflict explicitly (an upgrade, or a scoped override you can justify), then pin it with the lockfile
8. No rate limitingTry to log in 20 times in a minute with a wrong password. Call your most expensive endpoint, such as an AI feature, in a loopLimits per IP and per account on login, sign-up, password reset and anything that costs money per call
9. No database migrationsLook for migration files in the repository, and try to build the database from empty using only those filesCapture the current schema as a baseline migration, make every future change a migration, and replay them in CI
10. Cost blow-upsOpen the billing pages for AI APIs, hosting, database and email. Look for usage with no cap and endpoints that call paid APIs without loginSpending caps and billing alerts, authentication and rate limits in front of every paid call, caching of repeated results

Why are secrets and authorization the first two gaps to fix?

Because they are the two that expose other people's data, and neither shows up while you test alone. Everything else on the list costs you money or time; these two can cost your customers.

Secrets in client code

Anything in the browser is public. A key in the JavaScript bundle can be read by anyone who opens developer tools, whether or not the key is shown on screen. Some keys are designed to be public: a Supabase anon key, for example, is meant to be in the browser, but it is only safe when row-level security is doing its job. A service-role key, a payment provider's secret key or an AI provider's key must never reach the browser.

Authorization and row-level security

Authentication asks who you are. Authorization asks whether you may see this record. AI-generated apps usually get the first right and often skip the second, because the preview only ever has one user. The attack is simple: change an ID in a request and read someone else's order, invoice or message. Security teams call it insecure direct object reference, or IDOR, and the API security checklist covers the wider set of checks.

This is the area where RAITHub's own evidence is strongest. On Sundor Skin, a B2B wholesale platform RAITHub built with a 146-table PostgreSQL core, row-level security is enforced in the database, and CI replays all 76 migrations on an empty database and fails the build if any buyer-scoped table lacks an RLS policy. Its 530+ tests include an IDOR security suite that deliberately tries to read another buyer's data. The rule behind both: a forgotten policy on a new table should be a failed build, not a customer's discovery.

What goes wrong between preview and production?

Configuration, installs and schema. The code is often the same; the environment around it is not.

  • Config drift. Preview points at a test database and a test payment key; production needs different values, and one missing variable can leave a feature quietly broken. On the RAITHub website, the build fails if a required production variable is missing, so a half-configured deploy never goes live.
  • Installs. Local tools often install from the lockfile, while a host may resolve dependencies again. On 27 September 2026, a security upgrade to the RAITHub website passed every local check and failed on Vercel with ERESOLVE, because next-auth's peer range did not accept the new nodemailer version. The fix and its verification are in the next-auth and nodemailer ERESOLVE write-up.
  • Schema. AI tools and database dashboards make it easy to change tables by hand. Then production and preview disagree, and nobody can rebuild either from code. Migrations in the repository, replayed in CI, fix that.

Is schema validation enough to stop bad input?

It is necessary, but test what it actually outputs. Validation libraries have their own traps, and a schema that looks right can still change your data.

A real example from RAITHub's own website: the admin's update schemas used zod 4's .partial(), which still applies .default() values for fields you leave out. A request to move one item to a new position would also have unpublished it and wiped its images. Tests, type-checks and lint were all green; the bug was found by tracing one request from the button to the database, and fixed with a regression test per schema. The details are in zod 4 .partial() keeps default values. For an AI-generated app, the lesson is to test that an update changes only the fields you sent.

How do you stop a vibe-coded app from running up a huge bill?

Put a login and a rate limit in front of every call that costs money, and set spending caps before launch, not after the first invoice.

  • AI features are the usual culprit: an endpoint that calls a model on every keystroke, or one anyone can call without logging in.
  • Serverless loops such as a webhook that triggers itself, or a page that refetches on every render.
  • Database and storage egress from serving large files straight from the database.

Rate limits need care in the other direction too. On the RAITHub website, login was first rate-limited only per email address, which meant anyone who knew the admin's email could keep the admin locked out. It now uses three buckets: email plus IP, per IP, and per email across IPs. The rate limiting explainer covers the patterns.

Can you fix these gaps by prompting the AI tool again?

Partly. You can ask the tool to add row-level security, validation or tests, and it often will. What you cannot delegate to the same tool is the proof that the fix works.

Given the Stanford finding that AI assistance raised confidence along with the vulnerabilities, verify every fix with a test that attacks the gap: a second user trying to read the first user's record, a request with an extra "role" field, a login loop. If the test fails before the fix and passes after, the gap is closed. If there is no test, you have only the tool's word for it.

Which gaps must be fixed before launch?

WhenGapsWhy then
Before any real user data1 secrets, 2 authorization, 3 validation, 6 config drift, 9 migrationsThese expose or corrupt customer data, and are much harder to fix once data exists
Before paid traffic or a public launch8 rate limiting, 10 cost controls, 5 error trackingTraffic finds abuse paths and cost leaks within days
Continuously4 tests, 7 dependenciesEvery change and every upgrade can reopen a gap

For the full launch gate beyond security, use the pre-launch QA checklist; for Next.js specifics, the Next.js production checklist.

Has RAITHub rescued a vibe-coded app?

RAITHub has not published a case study of rescuing an AI-generated app, so this post does not claim one. The evidence above comes from platforms RAITHub built and from its own website, and it maps directly onto the gaps that AI-generated apps tend to have.

The method for taking over any unfamiliar codebase, generated or not, is the same: secure access, run a diagnostic, put tests around the critical paths, fix in risk order. It is set out in the Code Rescue Playbook.

Why RAITHub for a vibe-coded app?

  • The gaps are the ones RAITHub gates for. Row-level-security checks in CI, IDOR test suites, environment validation at build time, and the exact deploy install reproduced before a fix is called done.
  • Keep what the AI built well. Much of a generated app is fine. The diagnostic separates the parts to keep from the parts to harden, instead of starting again.
  • A fixed written quote after a free 15-minute technical audit. RAITHub publishes no rates.
  • Tests stay in your repository, with full IP assignment, so the next AI-generated change is checked by the same gates.

When do you not need RAITHub?

  • It is still a prototype for validating an idea, with no real user data. Keep iterating, and harden it once it has users.
  • The table above comes back clean and you have someone to maintain it. Keep the checks in CI and carry on.
  • You have one specific gap, such as a deploy error. That is a single fix, not a rescue: use "Fix a specific issue" on the contact form.
  • You need a certified vendor. RAITHub is not SOC 2 or ISO 27001 certified.

If several rows in the table failed, pick Code Rescue on the contact form and book the free 15-minute audit. Send the results of your 10-minute checks; they make the first call far more useful.

Last reviewed: 28 September 2026. External sources checked on 28 September 2026.

Frequently asked questions

Why is my Lovable app not working in production?

Usually because production differs from the preview: missing or different environment variables, a database without the right policies, a dependency that resolves differently on the host, or real users doing things the preview never tried. Compare environment variables first, then run the exact install and build commands your host uses.

What are the most common security issues in vibe-coded apps?

Secrets shipped to the browser, missing row-level security or ownership checks that let one user read another's data, and no server-side input validation. Veracode's 2025 report found that 45% of AI-generated code samples it tested introduced an OWASP Top 10 vulnerability.

Is the Supabase anon key a secret?

No. It is designed to be used in the browser, but it is only safe when row-level security is enabled with correct policies on every table. The service-role key is a secret and must never reach client code.

Do I need to rewrite my AI-generated app to make it production-ready?

Usually not. Most gaps are fixed in place: move secrets to the server, add authorization policies, validate input, add tests and logging, and capture the schema as migrations. A rewrite makes sense only when the data model fundamentally contradicts the business.

Can the AI tool fix its own security problems?

It can often write the fix when asked, but it cannot be the proof. Verify each fix with a test that attempts the attack, such as a second user requesting the first user's record, and keep that test running in CI.

How long does it take to make a vibe-coded app production-ready?

It depends on the size of the app and how many of the 10 gaps are open. The checks take about 10 minutes each; the fixes range from hours to a few weeks. RAITHub gives a fixed written quote after a free 15-minute technical audit.

vibe codinglovable app not working in productionvibe coded app security issuesAI-generated codeproduction readinessrow-level securitySupabase

Ready to discuss your project?

Book a free 15-minute technical audit with our engineering team.