Fix.

The vibe coded MVP audit checklist

A practical 6-point checklist to find hidden security flaws, exposed secrets, and database performance traps in AI-generated web applications.

8 min read

Modern AI tools make it possible to build an interactive web application in hours. Prompts produce working dashboards, authentication flows, and Stripe checkouts without writing boilerplate code by hand.

The issue is that AI models optimize for visual completion and immediate user feedback, not production security or edge case reliability. When early testers arrive, common architectural shortcuts create silent security breaches or crash database connections.

Before you launch an AI-generated product to paying customers, run your codebase through this six-point audit.

1. Inspect client bundles for exposed administrative keys

The single most dangerous failure in AI-generated full-stack software is embedding administrative credentials directly into client JavaScript.

AI tools frequently import backend clients into frontend components to make features work quickly. Inspect your built assets in dist/assets or your browser developer console:

  • Supabase service_role key: This key bypasses Row-Level Security entirely. If it appears anywhere in your client files, any visitor can open their browser console and delete your entire database.
  • Stripe restricted secret keys: Client checkouts should only use the publishable key (pk_live_...). A secret key (sk_live_...) in frontend code lets attackers issue unauthorized refunds or read transaction histories.
  • Third-party API tokens: OpenRouter, OpenAI, or Resend keys must always execute behind backend edge functions with user rate limits.

Run a search across your repository for service_role and sk_live. If found in files under src/components or src/pages, move the database logic to an edge function immediately.

2. Verify Row-Level Security on every public table

AI builders routinely create database tables without activating Row-Level Security (RLS), or generate blanket policies that permit anyone to read and write.

Run this query in your Supabase SQL editor to inspect all tables:

select 
  tablename, 
  rowsecurity 
from pg_tables 
where schemaname = 'public';

If rowsecurity is false on any table, anyone who discovers your public Supabase URL and anon key can query that table directly using the Supabase JavaScript client, completely bypassing your frontend interface.

For every table containing customer data, enable RLS:

alter table profiles enable row level security;
alter table payments enable row level security;

Then write specific policies for select, insert, update, and delete. Never rely on a single blanket policy for all operations.

3. Harden Stripe webhooks against forged payloads

Many AI prototypes mark invoices as paid based solely on client-side redirect query parameters (such as ?payment=success).

Attackers can trigger premium account upgrades simply by navigating directly to the success URL without paying a cent.

Production billing must rely exclusively on verified server-side webhooks:

  1. Never trust client redirects for account provisioning.
  2. Read the raw request body in your webhook handler.
  3. Validate the stripe-signature header against your production webhook signing secret (whsec_...).
  4. Reject requests where verification fails before updating database records.

Verify that your webhook endpoint is idempotent. If Stripe retries a webhook notification three times, your backend must not credit user accounts three times.

4. Eliminate unbounded queries and missing indexes

AI-generated database queries almost never include pagination limits. While a query like supabase.from('posts').select('*') runs fine with 10 test records, it crashes browser memory when your database reaches 5,000 records.

Audit your data fetching queries:

  • Ensure every list query contains .limit(50) and explicit offset or cursor pagination.
  • Filter only the exact columns required rather than using select('*').
  • Check foreign key columns. Postgres does not index foreign keys automatically. Add indexes to columns used in filters and joins (such as user_id and created_at) to prevent full table scans.

5. Validate client-side permission guards on the server

In prototype applications, AI models often hide administrative buttons by checking a user’s role in local state:

// Fragile: Client-only guard
{user.role === 'admin' && <DeleteUserButton />}

Hiding a button does not protect the underlying database record. Anyone can inspect the network request, copy the API endpoint, and send a direct DELETE request.

Every destructive operation must enforce permission checks on the database or edge function layer. The database must refuse the query even if a malicious user manipulates frontend state.

6. Configure error boundaries and connection fallbacks

When an external API times out or returns an unexpected schema, AI-generated React code frequently crashes into a white screen of death.

  • Wrap major routes in React error boundaries with human-readable error messages and retry buttons.
  • Handle database connection drops gracefully with exponential backoff.
  • Replace infinite loading spinners with explicit timeouts that notify users when a service is unreachable.

Getting an independent assessment

Auditing your own application can be difficult when launch deadlines are approaching.

If you have a prototype built with Lovable, Cursor, or Bolt that is heading to production, we provide an external technical diagnosis within 48 hours to pinpoint security vulnerabilities and architecture bottlenecks before your users encounter them.

About the author

Adeola Ilori founded Adeola Forge and leads its engineering work. The studio builds and fixes web apps, AI-built apps and automations.

More guides on fix

Have a project in mind?
Let's build it.

Whether you are building a new SaaS platform from scratch, launching a mobile product, designing a high-conversion interface, or need an urgent rescue for an AI-built app, we are ready to help. You will receive a clear scoped plan and milestone timeline within 1 to 2 business days.

100% code ownership/Direct founder access/Fixed milestones
WhatsApp us