Vibe coding security checklist before you launch
An AI coding tool has no concept of launch readiness. It produces code until you stop asking it to produce code, and the last thing it generates is as likely to have security gaps as the first. Without an explicit checklist, the security posture of an AI-built app is whatever happened to not crash during development — which is a very low bar for software that will store real user data and accept real payments. The checklist below covers the six categories that matter most in the first 90 days of a production application: authentication, environment variables, HTTP security headers, database access control, rate limiting, and observability. Working through it before you share your launch link takes less than an hour and closes the gaps that cause the majority of early-stage incidents.
Authentication is the category with the most subtle failure modes in AI-generated code. The surface issue is easy to spot — unprotected routes — but the more common problem is routes that look protected but aren't. Watch for five patterns: client-side redirects that redirect unauthenticated users from the UI while leaving the underlying API route open; session checks that run after data-fetching code, meaning the data has already been queried before the unauthenticated user is turned away; authentication checks that only verify that a token exists without verifying that the token belongs to a user who is authorized to access the specific resource being requested; API routes that accept a user_idparameter from the request body without confirming it matches the authenticated user's ID; and admin functionality that checks for a boolean isAdmin field from the client rather than from the server-side session. Each of these looks correct from the outside and fails under targeted testing.
Your environment variables are the keys to your entire infrastructure. Audit them before launch with three specific checks. First, review every variable that starts with NEXT_PUBLIC_ and confirm that it contains only credentials designed to be public — Stripe publishable keys, analytics write keys, the Supabase anon key. If a variable containing secret, service_role, sk_, or OPENAI has a NEXT_PUBLIC_ prefix, rename it immediately. Second, confirm your .env, .env.local, and .env.production files are in your .gitignore and have never been committed to your repository — check your git log if you are not certain. Third, rotate any key that has ever appeared in a public repository, regardless of whether you believe it was visible for a short time or has since been overwritten.
HTTP security headers are a ten-minute fix with a significant security impact. In a Next.js app, add them in your next.config.ts using the headers() async function. The minimum set you need is: X-Frame-Options: DENY to prevent clickjacking; X-Content-Type-Options: nosniff to prevent MIME sniffing;Referrer-Policy: strict-origin-when-cross-origin to control what information leaks in referrer headers; Strict-Transport-Security with a one-year max-age and includeSubDomains to enforce HTTPS; and a Content-Security-Policy that at minimum blocks inline scripts and limits which external origins can be loaded. After deploying, verify each header is present by running curl -I https://yourdomain.com and checking the response.
Every table in your database needs Row Level Security enabled and tested before launch. In Supabase, enable RLS in the table editor for each table, then write policies that restrict rows to their owners using auth.uid() = user_id. After adding policies, test them: switch to the anon role in the Supabase SQL editor and confirm a direct SELECT * FROM your_table returns zero rows. Also confirm your service role key is not accessible from client-side code — search your codebase for the key value and verify it only appears in server-side files. Storage buckets that hold user content should be set to private, with signed URLs generated server-side for access.
The final two categories — rate limiting and monitoring — are the ones most often deferred until after launch, by which point an incident has already happened. Rate limiting on authentication endpoints prevents credential stuffing; rate limiting on API endpoints prevents scraping and abuse. At minimum, add IP-based rate limiting on your login, signup, and password-reset routes before your first public user arrives. For monitoring, set up error tracking with Sentry or a similar service so you get alerted when unhandled errors occur in production — these often indicate that someone is probing your app in ways you did not anticipate. Enable Supabase's built-in logging and set up an alert for an unusually high volume of failed authentication attempts, which is the earliest signal of a credential stuffing attack.