VibeSecurity

Guide

Pre-launch security runbook for apps built with AI tools

This is a runbook, not a list of things to think about. It walks you from the days before launch to the first hours after it, in the order you should do things, and every row tells you exactly what to run or click and what result counts as a pass. By the end you will have a filled-in table proving your secrets, data rules, access checks, hosting and dependencies were verified on your own project.

By the VibeSecurity team8 min read

What you need and what you will have at the end

You need your repository, your hosting dashboard, your database or backend console, two test accounts with different roles or owners, and a terminal with curl, git and your package manager. Run everything on your own project and your own test data. If you find a problem in someone else's app, tell its owner privately and do not probe it.

Copy the tables below into a document and fill in a result and the date for every row. The finished document is your evidence that the checks happened, and it makes the next launch faster.

Phase 1: Several days before launch, secrets and repository

Start here because a leaked key is the most expensive mistake and the slowest to clean up. The detailed methods are in our guide on exposed API keys, and the rows below are the launch subset.

Secrets and repository
CheckCommand or click pathPass condition
No secrets in sourcegrep -rEn "sk_live_|service_role|BEGIN (RSA |EC )?PRIVATE KEY|postgres(ql)?://" . --exclude-dir=node_modules --exclude-dir=.gitNo hit is a real credential
Env files untrackedgit ls-files | grep -E '(^|/)\.env'No output
No secrets in the buildnpm run build, then grep the .next/static or dist folder for the same patternsNo matches
History clean or keys revokedgit log --all --oneline -S'sk_live_'No hit, or every hit's key has been revoked
Keys pasted into chats rotatedProvider dashboard, API keys page, expire and replaceOld key returns an authentication error
Spending limits setEach paid provider's billing or usage settingsA limit or alert exists for every paid API

Phase 2: The day before, database and storage

Browser apps that talk straight to a managed database depend on its rules. Use the section that matches your stack and skip the other. The Supabase and Firebase guides on this site have the full procedure and fixes.

Database and storage
CheckCommand or click pathPass condition
Supabase: RLS on everywhereSQL editor: select tablename, rowsecurity from pg_tables where schemaname = 'public'Every row is true, or a false row has a written reason
Supabase: anonymous read blockedcurl the REST URL for each table with only the publishable keyEmpty array or permission error
Supabase: buckets privateSQL editor: select id, public from storage.bucketsBuckets holding user files show public = false
Firebase: no open rulesConsole, Firestore, Storage and Realtime Database rules tabs, search for if trueNone found
Firebase: signed-out refusedRules Playground, simulate an unauthenticated readDenied
Cross-user isolationSign in as test user B, request user A's record by idNo data returned and no change made

Phase 3: The day before, access control and abuse

Broken access control means a signed-in user doing something they should not be able to do, and it is the flaw AI tools produce most often because a hidden button looks like a rule in the preview. Your test accounts are the way to prove otherwise. Use the browser's network tab to copy a real request, then replay it with the other account's session.

Access and abuse controls
CheckCommand or click pathPass condition
Admin routes enforced on the serverAs a normal user, request an admin API route directly with curl using that user's token403 or 401, never data
Ownership checked on changesAs user B, send an update or delete for user A's record idRejected, and the record is unchanged
Paid routes require sign-incurl your AI or payment route with no session401 response
Rate limiting on login and paid routesSend repeated failed logins from a script against your own login endpointYou are eventually refused, for example with a 429
Password reset and email confirmation onAuth provider settings, then run both flows with a test addressBoth emails arrive and both links work once
Server-side validationSend a malformed body directly to a write route with curl400 response, no record created
Errors leak nothingTrigger an error on purpose in production or previewNo stack trace, SQL or internal URL in the response

Phase 4: Launch morning, hosting and dependencies

Now the deployment itself. Headers are cheap to add, and a dependency audit takes minutes. Skip neither because they are boring.

Hosting and dependencies
CheckCommand or click pathPass condition
HTTPS only with HSTScurl -sI http://your-app.example, then curl -sI https://your-app.example | grep -i strict-transportHTTP redirects to HTTPS and HSTS is present
Baseline headerscurl -sI https://your-app.example | grep -iE 'x-content-type|referrer-policy|content-security'nosniff, a referrer policy and a frame-ancestors CSP are present
Debug and preview endpoints goneSearch routes and config for debug, test and seed paths, then request each on production404 or 401 for all
Test accounts and seed data removedAdmin or database console, filter by test emails and sample rowsNone left, or each is disabled and unprivileged
Dependency auditnpm audit --omit=dev --audit-level=highExit code 0, or every remaining finding is read and accepted in writing
Production env correctHosting dashboard, environment variables for the production scopeProduction keys are set, test keys are not, no secret has a public prefix

Phase 5: At go-live, production smoke test

Once the production deployment is live, run one short pass as an outsider and one as a real user. This catches configuration that only exists in production, such as a missing environment variable or a rule that was deployed to staging only.

  1. 1Open the site in a private window with no session. Confirm the pages that should be public load and the pages that should not redirect to sign-in.
  2. 2Create a fresh account with a real email address. Confirm the confirmation email arrives, the link works once, and a second use of the link fails.
  3. 3Complete the main action of your app, including a payment in test mode if you take payments. Confirm the record is created under the right owner.
  4. 4Sign in as the other test account and confirm you cannot see or change the first account's record.
  5. 5Open developer tools on the live site and search all sources for the secret patterns from Phase 1.
  6. 6Read your provider dashboards for the first few live requests and confirm they use production keys and limits.

Phase 6: The first hours after launch

Keep the runbook open. Watch your hosting logs and each provider's usage page for spikes and for errors you did not expect, because a leaked key or an open endpoint shows up first as unusual usage. Have the rotation steps for every key within reach, and know who on the team can revoke each one.

If something fails, revoke first and investigate second, then write the finding into the same table so it becomes a permanent row.

Common mistakes

  • Testing with your own admin account only, so every access check passes.
  • Running the checks on a preview deployment and assuming production has the same settings.
  • Skipping the second test account because creating one is tedious. It is the only way to test isolation.
  • Fixing the failed rows and not re-running the passed ones. A fix in one area can undo another.
  • Treating the dependency audit as noise. Read the high-severity results for packages that ship to production.
  • Leaving the filled-in table undone, then having no record of what was verified.

How to verify

The runbook passes when every row in Phases 1 to 4 has a recorded result and date, every failed row is either fixed and re-run or has a written exception, and the Phase 5 smoke test completed against the live site. Keep the document with your release notes.

Keep it working

Re-run Phase 1 whenever someone pastes a key into a chat with an AI tool or a teammate leaves. Re-run Phase 2 after any migration or rules change. Re-run Phases 3 and 4 before every release that adds a route, a role or a third-party service. Store the tables in your repository and treat each launch as an update to them.

Frequently asked questions

How long should a pre-launch security pass take?

For a small app, most of it is copying commands and reading results, and the slow parts are creating a second test account and reading dependency findings. Budget a focused block, then keep the filled-in table so the next launch only needs re-runs.

Which phase matters most if I am short on time?

Secrets and data rules, meaning Phases 1 and 2. A leaked secret key or a table without protection exposes everything at once, while the other phases limit narrower problems. Do those two first, then access control.

Do I need a security professional before launching?

Not necessarily for a small first release. This runbook covers the most common gaps in AI-built apps. If you handle payments, health data or other sensitive records, or hold regulated data, get a qualified review, and check the rules that apply to you.

Can I run these checks against a competitor or a friend's app?

No. Only test systems you own or have written permission to test. Probing someone else's app can be illegal even with good intentions. If you notice a problem in another app, report it privately to its owner.

Sources

  1. 1.OWASP Top 10
  2. 2.Supabase docs: Row Level Security
  3. 3.Firebase docs: Security Rules
  4. 4.npm docs: npm audit
  5. 5.OWASP HTTP Headers Cheat Sheet