AI Remediation
Is My AI-Built App Production-Ready? A 10-Point Checklist
July 5, 2026 · 9 min read · Anju Kumari
You built an app with Lovable, Replit, Cursor, Bolt, or v0. It works. It looks good. You're about to put real users — maybe paying users — on it.
Here is the uncomfortable part: "it works when I use it" and "it's production-ready" are different claims. Vibe coding is genuinely good at the first one. The AI optimizes for the demo — the visible feature, the happy path, the thing you asked for. Production-readiness lives in everything you didn't ask for: what happens when a stranger pokes at your URLs, when Stripe retries a webhook, when two hundred people show up at once. We've written about the underlying failure patterns in what breaks when AI builds your app; this post is the self-assessment version.
Ten checks. Most of them you can run yourself in five minutes, without reading code.
1. Can a logged-out user reach data they shouldn't?
Why AI tools get this wrong: AI-generated code often enforces login in the user interface — it hides the dashboard button — while the underlying API routes (the addresses your app's data actually travels through) stay open. The AI built what you could see. Nobody asked it to secure what you couldn't.
Check it yourself: Open a private/incognito browser window so you're logged out. Paste in direct URLs from inside your app — a dashboard page, a settings page. Then log in normally with developer tools open (right-click, "Inspect", Network tab), note the API addresses your app calls, and paste one into the incognito window.
What bad looks like: Any page or API address that returns real data instead of an error or a login redirect. If an incognito window can see it, so can anyone on the internet.
2. Can user A see user B's data?
Why AI tools get this wrong: This is authorization — not "are you logged in" but "is this yours." AI-generated queries frequently fetch records by ID alone: "get invoice 47" instead of "get invoice 47 if it belongs to this user." The ownership clause is invisible in a demo with one user. Tools built on Supabase (Lovable, Bolt) depend on row-level security policies — per-table rules about who can read what — that are easy to leave permissive or off entirely.
Check it yourself: Create two accounts. As user A, open one of your own records and look at the URL — there's usually an ID in it, like /invoices/47. As user B, change the number and load it. Try a few.
What bad looks like: User B sees user A's invoice. This is the single most common serious flaw in vibe-coded apps, and it's the one that ends up in a breach-notification email.
3. Are your payment webhooks verified and idempotent?
Why AI tools get this wrong: A webhook is a message a service like Stripe sends your app — "this customer paid." AI-generated webhook handlers commonly skip two things. First, signature verification: proving the message actually came from Stripe and not from anyone who found your webhook URL. Second, idempotency — handling the same message twice without double-acting, because Stripe will deliver duplicates. Both omissions are invisible in a test purchase.
Check it yourself: Worth five minutes of code reading even for a non-technical founder. Find the webhook file (search your project for "webhook") and look for the word "signature" or constructEvent. If it's absent, the endpoint trusts anyone. For idempotency, ask: what happens if this exact event arrives twice?
What bad looks like: No signature check means an attacker can send a fake "payment succeeded" message and get your product for free. No idempotency means a retried webhook grants double credits or sends duplicate emails.
4. Are your secret keys sitting in the browser bundle?
Why AI tools get this wrong: Your app has secret keys — for Stripe, OpenAI, your database. They belong on the server. But AI coding tools frequently wire API calls directly from the browser because it's the shortest path to working code — which ships the key to every visitor. In the frameworks these tools favor, any variable prefixed NEXT_PUBLIC_ or VITE_ is public by design, and the AI reaches for that prefix because it makes the error go away.
Check it yourself: Open your live site, view the page source (Ctrl+U or Cmd+Option+U), and search for sk_live, sk-, and the word secret. Then check the Network tab: does your browser talk to api.openai.com or api.stripe.com directly? It shouldn't — those calls should go through your own server.
What bad looks like: A key in the page source is public. Assume it's already harvested — bots scan for exactly this — and revoke it today, before fixing the code.
5. Does your app validate input on the server, or only in the form?
Why AI tools get this wrong: AI-generated forms usually validate in the browser — red text under the email field — and then trust whatever arrives at the server. But anyone can bypass your form and send data straight to your API. The AI validates where validation is visible; the demo never exercises the hostile path.
Check it yourself: Paste a 50,000-character string into a text field and submit. Enter a negative number where a price or quantity goes.
What bad looks like: The absurd input is accepted and stored. Worse: it changes something it shouldn't — a negative quantity that produces a negative total is a discount you didn't authorize.
6. Will the database survive your first hundred real users?
Why AI tools get this wrong: Two mechanisms. AI tools rarely add database indexes — the lookup structures that let a database find rows without scanning the whole table — because a table with 20 demo rows is fast either way. And AI-generated code loves the N+1 pattern: fetch a list, then run a separate query for each item, so a 50-item page fires 51 queries. Both are invisible until real data arrives, then everything slows down at once.
Check it yourself: This one mostly needs an engineer, but here's a proxy: if any page takes noticeably longer as you add data, that's the smell. On Supabase, the dashboard's query-performance section shows it — repeated near-identical queries in bulk is N+1 in the wild.
What bad looks like: Pages that took 200ms in the demo take 8 seconds with real data, and the fix is architectural, not a config toggle.
7. When something breaks, will you know?
Why AI tools get this wrong: AI-generated error handling has a signature move: wrap everything in try/catch, log to the browser console (which only that user sees), show a generic "Something went wrong," and move on. The error is swallowed, not reported. Nobody prompted for monitoring, so there is none.
Check it yourself: Ask one question: if a payment failed for a user last Tuesday, where would you look to find out? If the answer is "they'd email me," you have no answer.
What bad looks like: No error-tracking service (Sentry or similar) wired up, no server logs you know how to read, and failures that surface only as silent churn.
8. Do you have backups and a migration discipline?
Why AI tools get this wrong: Vibe coding encourages schema-by-conversation: ask the AI for a feature, it alters the database to suit. Fast — but there's often no migration history (a versioned record of every database change), no way to rebuild your database from scratch, and no verified backup. Plenty of vibe-coded apps have exactly one database, and the AI edits it live.
Check it yourself: Three questions. Do you have a backup you have actually restored once, to prove it works? Are database changes recorded in migration files, or made ad hoc through a dashboard or chat? Is there a separate database for development, or does testing touch production data?
What bad looks like: One database, no tested restore, schema changes applied conversationally. One wrong prompt — "clean up the users table" — from unrecoverable.
9. Do you know what your dependencies are doing?
Why AI tools get this wrong: AI-generated code pulls in packages liberally and sometimes hallucinates package names — a real attack surface, since squatters publish malicious packages under exactly those plausible names. Nobody reviews the dependency list, because nobody wrote it. Versions freeze at whatever the AI chose, and known vulnerabilities accumulate.
Check it yourself: If your project is on GitHub, open the Security tab — Dependabot alerts are free and specific. Or run npm audit in the project folder and read the summary line.
What bad looks like: Dozens of unpatched vulnerabilities, or packages nobody can explain the purpose of.
10. Can one bad actor take you offline or run up your bill?
Why AI tools get this wrong: Rate limiting — capping how many requests one user can make — is never part of "build me a signup form," so it's never built. The demo has one polite user. Production has scripts. Any endpoint that triggers cost is a target: login forms (password guessing), signup emails, and above all anything that calls a paid AI API on the user's behalf.
Check it yourself: Log in with a wrong password 30 times fast. Does anything slow you down or lock the attempt? If your app has an AI feature, could you hit it 500 times in a row? Then check whether your OpenAI/Anthropic account has a spending cap set.
What bad looks like: Nothing throttles you. For an app that resells AI calls, the failure mode isn't downtime — it's the invoice.
The scorecard
| # | Check | You can check yourself | Needs an engineer |
|---|---|---|---|
| 1 | Logged-out access to data | Yes — incognito test | To fix |
| 2 | User A seeing user B's data | Yes — two-account test | To fix |
| 3 | Webhook verification + idempotency | Partly — search for "signature" | Yes |
| 4 | Secrets in the browser bundle | Yes — view source + Network tab | To fix properly |
| 5 | Server-side input validation | Partly — absurd-input test | Yes |
| 6 | Indexes and N+1 queries | Mostly no | Yes |
| 7 | Error handling and logging | Yes — the "last Tuesday" question | To set up well |
| 8 | Backups and migrations | Yes — three questions | To fix |
| 9 | Dependency hygiene | Yes — GitHub Security tab / npm audit | To remediate |
| 10 | Rate limiting | Yes — the 30-tries test | Yes |
Scoring is simple. Zero or one failure: fix it and ship. Two: fix both before real users arrive, especially if either is #1–#4. More than two: you don't have isolated bugs, you have a pattern — and the checks you can't run yourself tend to fail in the same codebases as the ones you can.
Past two failures, guessing at priority order is where founders burn weeks. Our fixed-price code audit — from $995, five business days, written report — runs all of this against your actual codebase and hands you the list: what's dangerous, what can wait, and what it costs to fix. No hourly meter; you know the price before we start.
Related: read the auth security breakdown · book a vibe coding audit
Talk to us about your project
Senior engineers, honest scoping, fixed prices — quoted before work starts, paid when you approve the result.
Start a conversation →