# Audit an AI-built app — Lovable, Bolt, Replit, v0, Firebase Studio, Cursor & Windsurf

Built your app with an AI app-builder? Those tools scaffold a predictable stack with a **predictable
set of security holes**, and the `vibe` profile leads with exactly those, so a check finds them
first. There are two kinds of platform here:

- **Builders** (Lovable, Bolt, Replit, **v0**, **Firebase Studio**) — they scaffold a whole app on a
  known stack, so there's a repo and a deploy URL to point at. For each you get all three: the MCP
  setup, the import flow (paste the repo **or** the deployed URL), and the `vibe` checks for that
  stack.
- **Editors** (**Cursor**, **Windsurf**) — AI code editors that produce **any** stack on whatever
  repo you have open, so there's no single "import" target. For these the integration is **purely the
  MCP**: the editor's agent calls lens inline on the open repo. No import flow needed.

The original three (Lovable, Bolt, Replit) scaffold a Vite/Next + React + Tailwind + Supabase stack;
v0 builds Next.js on Vercel; Firebase Studio builds on a Firebase backend. The `vibe` profile leads
with the characteristic holes of each.

**What the `vibe` profile checks:**

- **Client-exposed keys** — a service-role/secret key shipped to the browser behind a `VITE_` /
  `NEXT_PUBLIC_` prefix (an anon/publishable key is meant to be public and is fine; a secret one is
  bundled into client JS and is **critical**), plus API keys hardcoded in client components.
- **Supabase with no RLS** — tables anyone with the public anon key can read/write, Row-Level
  Security policies written as `USING (true)` (no real protection), public storage buckets, and the
  service-role key used in client/browser code.
- **Missing auth** — API routes, Supabase edge functions, and Next.js server actions / route
  handlers with no authentication or ownership check; queries that trust a client-supplied user id.

You can run the `vibe` profile three ways: from the **Audit an AI-built app** card in the web app,
from your AI agent over **MCP**, or from the **API**. Each goes through the same token-metered flow
(a free estimate sizes + prices it; spend happens only when you commit) and the same ownership
gating (the target must be on your allow-list, or a connected GitHub repo).

> **A note on logos.** The web app surfaces these platforms by **name only** (text chips with a
> logo-ready slot). Official brand logos are **intentionally deferred** pending (a) official brand
> assets and (b) a per-platform brand-guideline review — we won't scrape or approximate a mark.
> Everything is framed as "audit apps **built with** X" (compatibility); lens is an independent
> tool, not affiliated with, endorsed by, or sponsored by any of these platforms.

## How to audit, via the import flow

Open the app, and on the start screen choose **Audit an AI-built app**. Paste **either**:

- your project's **GitHub repo** — e.g. `github.com/you/your-app` → we review the **code**
  (repolens), or
- your **deployed app URL** — e.g. `https://your-app.lovable.app` → we review the **live site**
  (sitelens).

We detect which from the URL (a `github.com/owner/repo` URL is a repo; any other web URL is a
deployed site), pick the right lens, and run the `vibe` profile automatically. You then see a free
estimate, pick what to run, and commit — the normal pricing and spend limit apply.

## Per-platform setup

For a **builder** (Lovable, Bolt, Replit, v0, Firebase Studio): (a) wire lens into the platform's AI
agent over MCP so it can audit inline, (b) audit via the import flow (paste the repo **or** the
deployed URL), and (c) the `vibe` checks for that stack (client-exposed keys, no-RLS / open backend
rules, missing auth — above).

For an **editor** (Cursor, Windsurf): there's just the MCP. The editor produces any stack on whatever
repo is open, so there's no import target — you add the `mcpServers` block to the editor and its agent
calls lens on the open repo. Same MCP config, no import flow.

The MCP config block is the same everywhere — only **where you paste it** differs. Get a key from
your lens account's **Developers** view, then drop this into the platform's MCP / `mcpServers`
config (replace the URL with your lens-web base URL and the key with your `lens_sk_…` key):

```json
{
  "mcpServers": {
    "lens": {
      "command": "lens-mcp",
      "args": [],
      "env": {
        "LENS_API_URL": "https://app.uselens.example",
        "LENS_API_KEY": "lens_sk_your_key_here"
      }
    }
  }
}
```

Then ask the agent, e.g. _"audit my repo with lens"_ or _"audit https://your-app.lovable.app with
lens"_. The MCP server is a thin client of the audit API — it runs the hosted audit and returns the
verdict (overall grade, per-dimension grades, the serious findings with fixes, a report link). See
[`lens-mcp`](../../lens/packages/lens-mcp/README.md) for the full reference.

### Lovable

- **MCP setup.** Add the `mcpServers` block above under your Lovable project's MCP / integrations
  settings, so Lovable's Chat agent can call lens inline.
- **Import flow.** In **Audit an AI-built app**, paste your GitHub repo (`github.com/you/your-app`)
  **or** your deployed app URL (`https://your-app.lovable.app`). We detect which and run `vibe`.
- **What `vibe` checks.** Client-exposed `VITE_…`/`NEXT_PUBLIC_…` secrets, Supabase tables with no
  RLS, and unauthenticated API routes / edge functions — see the list at the top.

### Bolt

- **MCP setup.** Add the `mcpServers` block above to your Bolt workspace's MCP settings
  (bolt.new / Bolt in StackBlitz), so the Bolt agent can call lens.
- **Import flow.** In **Audit an AI-built app**, paste your GitHub repo (`github.com/you/your-app`)
  **or** your deployed app URL (e.g. `https://your-app.netlify.app`). We detect which and run `vibe`.
- **What `vibe` checks.** Client-exposed secrets, Supabase no-RLS, and missing auth — see the top.

### Replit

- **MCP setup.** Add the `mcpServers` block above to your Repl's MCP config (or your editor's
  `.mcp` config), so Replit Agent can call lens.
- **Import flow.** In **Audit an AI-built app**, paste your GitHub repo (`github.com/you/your-app`)
  **or** your deployed app URL (e.g. `https://your-app.replit.app`). We detect which and run `vibe`.
- **What `vibe` checks.** Client-exposed secrets, Supabase no-RLS, and missing auth — see the top.

### v0 (Vercel) — builder

v0 builds **Next.js on Vercel** and syncs the generated code to a GitHub repo.

- **MCP setup.** Add the `mcpServers` block above to your MCP host so v0's agent can call lens (v0
  reads MCP servers from the same `mcpServers` JSON; add the block under its integrations / MCP
  settings).
- **Import flow.** In **Audit an AI-built app**, paste **either** the **GitHub repo v0 syncs to**
  (`github.com/you/your-v0-app` → we review the code) **or** the **Vercel deploy URL**
  (`https://your-app.vercel.app` → we review the live site). We detect which and run `vibe`.
- **What `vibe` checks (Next.js stack).** `NEXT_PUBLIC_` exposure — a secret shipped to the browser
  behind a `NEXT_PUBLIC_` prefix is bundled into client JS and is **critical** (a publishable key is
  fine); and **server-action / route-handler auth** — Next.js Server Actions and App Router route
  handlers (`app/**/route.ts`) with no authentication or ownership check, plus queries that trust a
  client-supplied user id.

### Firebase Studio (Google) — builder

Firebase Studio builds on a **Firebase backend** (Firestore / Auth / Storage / Cloud Functions).

- **MCP setup.** Add the `mcpServers` block above to Firebase Studio's MCP / agent settings so its
  AI agent can call lens inline.
- **Import flow.** In **Audit an AI-built app**, paste **either** your **GitHub repo**
  (`github.com/you/your-app` → we review the code) **or** your deployed app URL (e.g.
  `https://your-app.web.app` / `…firebaseapp.com` → we review the live site). We detect which and run
  `vibe`.
- **What `vibe` checks (Firebase backend).** **Open Firestore / Storage rules** — `allow read, write:
  if true;` (or rules that never check `request.auth`), the equivalent of no-RLS; and **an admin
  credential in client code** — a Firebase **Admin SDK** service-account key or other secret bundled
  into the browser is **critical**, while the **benign public config** (`apiKey`, `authDomain`,
  `projectId` in `firebaseConfig`) is meant to be public and is fine — lens distinguishes the two so
  the public config doesn't false-positive.

### Cursor — editor

Cursor is an **AI code editor**, not a builder: it produces **any** stack on whatever repo you have
open, so there's **no import flow** — the integration is purely the MCP.

- **MCP setup (the whole integration).** Add the `mcpServers` block above to Cursor's MCP config
  (Settings → MCP, or a `.cursor/mcp.json` in the project), so Cursor's Agent can call lens **inline
  on the open repo**. Then ask the agent, e.g., _"audit this repo with lens"_ — it runs the hosted
  audit and returns the verdict in chat.
- **No import flow.** Because Cursor edits any project, point lens at the repo (or deployed URL) the
  Agent is working on; there's no single platform import target.
- **What `vibe` checks.** Whatever the open project's stack is — `vibe` still leads with
  client-exposed secrets, no-RLS / open backend rules, and missing route/action auth (see the top).

### Windsurf — editor

Windsurf is an **AI code editor** (Codeium's), not a builder: same as Cursor — any stack, **no import
flow**, the integration is purely the MCP.

- **MCP setup (the whole integration).** Add the `mcpServers` block above to Windsurf's MCP config
  (Settings → Cascade / MCP, the `mcp_config.json`), so the Cascade agent can call lens **inline on
  the open repo**. Then ask, e.g., _"audit this repo with lens"_.
- **No import flow.** Point lens at the repo (or deployed URL) Cascade is working on; there's no
  platform import target.
- **What `vibe` checks.** Whatever the open project's stack is — client-exposed secrets, no-RLS /
  open backend rules, and missing auth (see the top).

## From the API

The `vibe` profile is just a profile, so the standard audit API takes it directly. Start an
estimate (free) and commit, or one-shot `POST /audits` (see [api.md](api.md)):

```bash
# free estimate — paste the repo OR the deployed URL as the target
curl -X POST https://app.uselens.example/audits/estimate \
  -H "Authorization: Bearer lens_sk_..." \
  -H "Content-Type: application/json" \
  -d '{"lens":"repolens","target":"https://github.com/you/your-app","profile":"vibe"}'
```

Use `"lens":"repolens"` with a repo URL, or `"lens":"sitelens"` with the deployed app URL. The
profile is metered and priced exactly like any other run.
