How to Fix a Vibe-Coded App: The 30-Minute Diagnostic
Ehtisham ul Haq
Founder of SeedInov. AI engineer building production-ready AI systems for businesses in 8 countries.

You built the whole thing in a weekend. It works, it looks good, and someone has just asked if they can pay for it. That is the moment the question changes from "does it run?" to "is this safe to put in front of real people?". This guide is how to fix a vibe-coded app: six checks you can run yourself in about thirty minutes, a rule for deciding whether to repair or rebuild, and the order to fix things in so you are never polishing code while customer data leaks.
No sales pitch until the end. Run the checks first. Most of what you find, you can fix yourself.
Why vibe-coded apps break in production
Vibe coding means describing what you want to an AI tool like Lovable, Bolt, Cursor, Replit or v0 and shipping what it returns. It is genuinely good at the first seventy percent. The mistake is assuming the last thirty percent does not exist because the demo looked finished.
AI coding tools optimise for code that runs, not code that survives. Veracode's 2025 GenAI Code Security Report tested more than 100 models across 80 coding tasks and found roughly 45% of AI-generated code introduced an OWASP Top-10 vulnerability. Other industry analysis through 2025 and 2026 points the same way: AI-assisted teams ship several times faster, and accumulate security findings faster still.
That ratio is not an argument against the tools. It is an argument for a checkpoint between "it works on my laptop" and "strangers can sign up". The failures cluster in exactly the places a demo never exercises:
- Authorization is checked in the interface and never on the server.
- Secrets end up hardcoded, committed, or shipped to the browser.
- Error paths get wrapped in empty catch blocks, so failures are silent.
- Money paths like payment and quota logic were never tested against a hostile input.
- Scale is an afterthought: no indexes, no caching, no rate limits. Fine at ten users.
Nobody prompts for these, because nobody demos them.
The 30-minute diagnostic: six checks
Work through these in order. Write down pass or fail for each, because you will use the tally at the end. You do not need to be a developer to run them, but you do need terminal access to your project and access to wherever it is deployed.
Check 1: are your secrets exposed?
This is check one because it is the only failure that stays dangerous after you fix the code. A key committed six months ago is still in the git history even if the current file is clean.
Scan the working tree:
npx secretlint "**/*"
Then scan the history, which is where the real surprises live:
git log -p | grep -Ei "sk-|AKIA|BEGIN (RSA |EC )?PRIVATE KEY|password\s*="
Finally, check what you are shipping to the browser. Anything with a client-visible prefix is public to every visitor, no matter what it is called:
grep -rE "^(NEXT_PUBLIC|VITE|REACT_APP)_.*(KEY|SECRET|TOKEN|PASSWORD)" .env*
Fail if: any real credential appears in any of the three. A service-role database key with a public prefix is a full compromise, not a warning.
Check 2: is your API actually protected?
This is the most common serious finding, and the fastest to test. Take any API route that returns private data and call it with no credentials at all:
curl -s -o /dev/null -w "%{http_code}\n" https://yourapp.com/api/orders
A 401 or 403 is what you want. A 200 means anyone on the internet can read that endpoint, and the login screen in front of it is decoration.
Then run the second half, which catches the subtler version. Log in as a normal user, open any page that shows something belonging to you, and change the ID in the URL or request to one belonging to a different account. If you can see their data, authorization is being checked in the interface rather than on the server. The AI hid the button, but the endpoint still answers.
If you are on Supabase, which is the default for Lovable and Bolt, open the table editor and confirm Row Level Security is enabled on every table holding user data, and that no policy is a permissive catch-all. RLS switched off is the Supabase-shaped version of this same bug.
Fail if: any private endpoint answers without credentials, or any user can read another user's records.
Check 3: what is in your dependencies?
AI tools pin whatever version was in their training data, which is often not the version you want.
npm audit --audit-level=high
Python projects:
pip-audit
Fail if: anything critical or high has a fix available. These are usually a one-line upgrade, so this is the cheapest check on the list to clear.
Check 4: what does static analysis find?
Static analysis catches the patterns AI generates with real consistency: SQL built by string concatenation, missing input validation, unsafe rendering of user content. Install Semgrep with pip install semgrep or brew install semgrep, then run the OWASP ruleset against your project:
semgrep --config=p/owasp-top-ten .
Fail if: there are ERROR-severity findings in code that touches authentication, user input, or the database. Ignore the noise in generated files and dependencies for now.
Check 5: do you have any safety net at all?
Two commands and one folder listing:
npm test and ls .github/workflows
If the first prints "no test specified" and the second does not exist, every deploy you make is a live experiment on your users. You do not need high coverage. You need tests on the three to five paths that make you money or lose you customers: sign up, log in, the core action, and checkout.
Fail if: there is no automated check between your keyboard and production.
Check 6: is the data model sound?
This is the expensive one, and it is not a command. It is three questions asked honestly against your schema.
- Can you name every table and say in one sentence what it holds? Tables nobody can explain are tables that grew by accident.
- Is any single fact stored in more than one place? Duplicated truth means every future feature is also a synchronisation bug.
- Do relationships exist as real foreign keys, or only as matching strings that application code hopes will line up?
Fail if: two or more of the three are a no. Keep this result separate from the others, because it drives the next decision on its own.
How to read your results
Tally the six checks:
- Checks 1 or 2 failed: stop taking new signups or payments until they are fixed. These are the two that expose customer data, and neither takes more than a day to close.
- Checks 3, 4 or 5 failed, 1 and 2 passed: you are not in danger, you are in debt. This is roughly a focused week of work and it is entirely doable in-house.
- Check 6 failed: read the next section carefully. This is the only failure that can make repair the wrong answer.
- All six passed: genuinely well done. That is rarer than the internet suggests. Add monitoring and move on to building.
Repair or rebuild? Use the data model as the line
Every rescue conversation eventually becomes "should we just start over?", and it is usually answered by mood rather than by evidence. There is a cleaner rule:
If the schema survives, repair. If the schema has to change, rebuild the layers above it.
The reasoning is mechanical. Missing authorization, exposed secrets, absent error handling and missing tests are all additive fixes. You are adding something that was never there, and nothing else has to move. A two-week rescue clears all of them without touching your features.
A wrong data model is different. Fixing it means migrating the data, which means rewriting every query, which means rewriting the service layer above those queries. At that point you are rebuilding anyway, and doing it deliberately is cheaper than doing it accidentally over six months of patches.
Two things feel like rebuild triggers but are not: ugly code, and a framework you have gone off. Ugly code that is correctly structured is a refactor you can do gradually while shipping. Wanting a different framework is a preference, and preferences are the most expensive reason to restart a working product.
Fix in this order, not the order you want to
The most common mistake at this stage is starting with a refactor, because tidying is satisfying and security is not. Tidy code that leaks customer data is still leaking customer data. Work top down:
- Rotate every exposed secret. Rotate first and scrub the git history second. Rotation is what actually stops the leak; history cleanup just stops it happening again.
- Enforce authorization on the server. Every route, every time, checked against the authenticated user rather than a parameter the client sent you.
- Harden the money paths. Payments, credits, quotas and anything that emails a customer. Validate on the server, and never trust a price or quantity that arrived from the browser.
- Add real error handling and error tracking. Replace empty catch blocks, then install Sentry or equivalent. It takes about twenty minutes and turns "a user said it broke" into a stack trace.
- Add CI and tests on the critical paths. A pipeline that runs on every push, plus end-to-end tests on your three to five money paths.
- Add uptime and log monitoring. You should learn your app is down from a notification, not from a customer.
- Then performance and cost. Database indexes, caching, rate limits, and bounds on LLM calls. Unbounded model calls are how a viral week produces a five-figure invoice.
- Refactor last, and only what you touch. Structure improves as you work through the list above. A big-bang rewrite of working code buys you nothing a user can see.
What each AI tool tends to get wrong
The failure patterns differ by where the code came from, which is a useful shortcut when you know your tool but not your codebase.
- Lovable and Bolt: Supabase by default, so the recurring issue is Row Level Security. It is either off entirely, or a policy is permissive enough that the public key reads every row. Check RLS table by table before anything else.
- Replit: secrets management is handled well by the platform, so the usual gap is deployment config. Development settings, permissive CORS, or debug modes get carried into the live environment.
- Cursor, Claude Code and Windsurf: you are in a real repository with generally better code, and the failure is architectural drift instead. Each session adds a new pattern, so you end up with four ways of doing the same thing and no single source of truth.
- v0: interface-first, and very good at it. The gap is behind the screens, where backends are stubbed or mocked, so the parts that look finished are not actually wired to anything.
- ChatGPT or Claude by copy-paste: individually reasonable files with no shared architecture, because no single prompt ever saw the whole system.
When to bring in a senior engineer
Most of this list is genuinely self-serve, and you should do the parts you can. Bring in help when one of these is true:
- Check 2 failed and you are not certain you have found every route it affects.
- You handle payments, health data, or anything covered by a regulator.
- Check 6 failed and the repair-or-rebuild call is worth more than the cost of a second opinion.
- You have paying customers now, and downtime costs more per day than the fix.
- You have tried to fix it with the same AI tool twice and the bug moved rather than went away.
That last one is worth sitting with. AI tools are excellent at adding code and poor at deciding what should not exist. When a fix produces a new bug two files away, you have hit the limit of what more prompting will solve.
The bottom line
Vibe coding got you a working product in a weekend, and that is a real advantage. The version of you that spent four months writing a spec is still writing the spec. Nothing here says the tools were the wrong choice.
What it says is that there is a checkpoint between working and safe, and the checkpoint is about thirty minutes long. Run the six checks. Fix the two that expose data. Use the schema rule to decide how far the rest goes.
If you would rather have someone else do it, our vibe code rescue service runs this same diagnostic properly and gives you a written report in three business days for a fixed $1,500, credited in full against the fix if you go ahead. If you have not built the thing yet, our 30-day AI MVP sprint gets you there without the cleanup bill. Or just book a free 20-minute triage call and we will tell you which of the three you actually need.


