← playbook6 min read

Playbook · Workflow

The pre-launch security checklist for vibe-coded apps.

AI builds the app. It does not ship it for you.

The reason vibe-coded apps get into trouble in production is almost never something exotic. It is a key that ended up in the frontend bundle, a privacy policy that never got written, an unauthenticated endpoint somebody else discovered before the team did. None of these are advanced problems. They are the boring pre-flight checks AI coding tools do not run for you, because shipping a product is not the prompt they were optimized for.

The nine items below are the minimum sweep. None of them require security expertise. Each one, on its own, is small. The compounded form is what people mean when they say a launch went badly.

§01Privacy is a legal posture, not paperwork

If your app collects anything that could identify a user, including IP addresses, email signups, analytics events, or session cookies, you are operating inside GDPR, CCPA, and a growing list of regional regulations whether you wanted to or not. The bar at launch is not perfection. It is not being reckless.

The pre-launch checks here are short. A privacy policy exists and is linked somewhere a user can find it. You can articulate, in one sentence, where user data is stored and how long you keep it. You are not silently reading from anywhere a user would not expect, the clipboard or the microphone, without telling them.

Most vibe-coded apps skip this because it does not feel like building. It is building. It is the part that keeps the rest of the building legal.

§02Security headers are free

Browsers will enforce a remarkable amount of security for you, if you remember to ask. The way you ask is HTTP response headers: Content-Security-Policy, Strict-Transport-Security, X-Content-Type-Options, X-Frame-Options, Referrer-Policy. None of these require you to write security code. They require you to set five strings.

Any decent AI coding tool will configure them correctly if you ask. The prompt that works:

Review my app as a security specialist and configure strong response headers and a solid baseline security posture for production.

This is the smallest-effort, highest-payoff item on the checklist. It is also the most reliably skipped, because it does not show up in any feature spec and nobody notices it is missing until the audit.

§03The OWASP sweep

Headers cover the perimeter. They do not cover the application logic. For the logic, the standard sweep is against the OWASP Top 10, which is the closest thing the web has to a canonical list of ways apps get broken.

The prompt:

Review my app against the OWASP Top 10 and highlight vulnerabilities in authentication, access control, injection, and configuration.

Four shapes are worth hunting for specifically. SQL injection lives anywhere user input flows into a query string without parameterization. XSS lives anywhere user input is rendered without escaping, which includes innerHTML, dangerouslySetInnerHTML, and server-rendered templates with raw interpolation. Auth and session handling covers token storage, password hashing, session expiry, and password reset flows. Broken access control is the most overlooked of the four: endpoints that check authentication but not authorization, the I am logged in, therefore I can read /api/users/42 shape.

AI tools catch most of these because the patterns are well-known. They miss the subtle ones. The goal of the sweep is not to be vulnerability-free. It is to not be obviously vulnerable.

§04Keep secrets out of the frontend bundle

The next three checks are the leak audit, which is the part AI-generated code is uniquely bad at. Working code is easy to demand. Code that does not accidentally leak things requires noticing what is not there, and noticing absences is harder for both humans and models.

The first place to look is the build itself. .env values prefixed with NEXT_PUBLIC_ or VITE_ ship to the browser, and if a secret has the wrong prefix, it is now public. Open your built bundle in devtools, search for the literal string of your API keys, and if you find them, rotate everything before doing anything else.

§05Trim what API responses return

The lazy way to build an endpoint is to return the whole user object. The whole user object usually includes hashed passwords, internal IDs, OAuth tokens, internal flags, and the notes column you forgot existed. Return only the fields the client needs.

This is also the cheapest performance optimization you will ever make. A lean response is smaller in the network tab and faster to render on the client, and you pay for the difference on every request.

§06Scrub credentials from logs

Every console.log(user) is a potential leak. Every error stack trace is a potential leak. The default behavior of most logging libraries, and of most AI-generated error handlers, is to dump the full object that triggered the error. If the object is a request, the request includes headers. If the headers include Authorization, the credential is now in the log.

Centralize logging. Run scrubbers on the way out, not on the way in. The scrubbers want a list of known sensitive keys, authorization, cookie, password, token, apiKey, and a default-deny posture for anything that looks like a JWT or a long random string.

The prompt that covers all three:

Check my app for credential or sensitive data leaks in frontend code, API responses, and logs.

§07Keys belong on the server

If an API key is in the browser, it is compromised. Not might be. Is. A network tab is one keyboard shortcut away from anyone with the URL of your app, and a model that helped you scaffold the integration will cheerfully suggest putting the key wherever the import works.

The fix is structural, not careful. Move the key to a server route or edge function. Have the browser call your server, and have your server call the third-party API. Treat any key that has ever been in client code as burned, and rotate it.

◆ pull quote

If a key is in the browser, assume it has already been taken. The fix is structural, not careful.

§08Rate caps on every paid route

The moment your server proxies a paid API on behalf of the browser, you have created a way for someone else to spend your budget. A loop on a stranger's laptop hitting your /api/chat endpoint costs them nothing and costs you whatever your provider charges per token, times however long the loop runs before anyone notices.

The cap belongs on the middleware that wraps every server route that calls a paid API. Per-IP and per-user limits handle the easy abuse cases. Per-endpoint caps weight more heavily on the routes that hit expensive models. The right cap is the one that lets a real user be productive and stops a script after a handful of requests.

§09Spend alerts before the bill

Rate caps are the first line. The second is a hard daily ceiling on outbound spend, set at the provider level when possible, and an alert that fires before the ceiling, not after. A provider-level cap matters because it survives a middleware bug. If the rate-cap layer fails open, the bill still has a floor on how bad it can get.

This is a few lines of middleware and a console setting. It is the difference between waking up to a normal Tuesday and waking up to a five-figure bill from a provider you have barely launched on.

The pre-flight pass

None of the nine items above are advanced. None of them are optional. The reason vibe-coded apps get into trouble in production is not that their builders do not know about CSP headers or SQL injection. It is that AI coding tools build features, and the pre-launch pass is the work that lives outside the feature spec. That work is still yours to run.

Spend an hour on the list before you ship. You will already be ahead of most early-stage launches.

◇ summary · field notes
$ vibgineer summarize pre-launch-security-checklist
  1. 01
    Privacy posture
    • privacy policy exists
    • know where data is stored
    • nothing collected silently
  2. 02
    Security headers
    • CSP
    • HSTS
    • X-Frame-Options
    • X-Content-Type-Options
    • Referrer-Policy
  3. 03
    OWASP sweep
    • SQL injection
    • XSS in rendered output
    • auth and session handling
    • broken access control
  4. 04
    Frontend bundle
    • no .env in client code
    • grep the build for keys
    • rotate anything found
  5. 05
    API responses
    • minimize fields returned
    • never the whole user object
    • cheapest perf win you have
  6. 06
    Logs
    • centralize logging
    • scrub credentials in transit
    • no raw user dumps
  7. 07
    Keys server-side
    • no client-side API keys
    • proxy through a server route
    • rotate anything ever in client
  8. 08
    Rate caps
    • per-IP and per-user limits
    • per-endpoint by cost
    • middleware on every paid route
  9. 09
    Spend alerts
    • hard daily ceiling
    • alert before the ceiling
    • cap at provider level
✓ 9 checks · the pre-flight pass before launch
Summary: Step 01: Privacy posture (privacy policy exists, know where data is stored, nothing collected silently). Step 02: Security headers (CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy). Step 03: OWASP sweep (SQL injection, XSS in rendered output, auth and session handling, broken access control). Step 04: Frontend bundle (no .env in client code, grep the build for keys, rotate anything found). Step 05: API responses (minimize fields returned, never the whole user object, cheapest perf win you have). Step 06: Logs (centralize logging, scrub credentials in transit, no raw user dumps). Step 07: Keys server-side (no client-side API keys, proxy through a server route, rotate anything ever in client). Step 08: Rate caps (per-IP and per-user limits, per-endpoint by cost, middleware on every paid route). Step 09: Spend alerts (hard daily ceiling, alert before the ceiling, cap at provider level). ✓ 9 checks · the pre-flight pass before launch