AI tools make shipping fast. Security review usually gets skipped — not because developers don't care, but because there is no clear, AI-specific checklist to run through before going live.
This is that checklist. It covers the patterns that appear most frequently in independent audits of Lovable, Bolt, Cursor, and Claude-built apps. Run through it before you share your URL with anyone.
Skip the manual work: VibeScan runs items 1, 3, 7, 9, and parts of 2 and 6 automatically — paste your URL, get results in 30 seconds, no GitHub access needed.
1. No secret keys in client-side code
What to check: Open your deployed app in a browser. DevTools → Sources → search for sk_, SUPABASE_SERVICE, openai, stripe, database hostnames, and any other key prefixes you use.
What's safe: The Supabase anon key (prefixed NEXT_PUBLIC_) is designed to be public. Everything else — service role key, Stripe secret, OpenAI key, database connection strings — must be server-side only.
Why it matters: VibeScan's May 2026 early sample contained 14 critical findings, including live Stripe secrets and Twilio credentials visible in public JavaScript bundles.
2. Supabase RLS is on AND the policies are correct
What to check: Supabase Dashboard → Authentication → Policies. For every table with user data, read the USING clause of each SELECT policy.
Red flags:
USING (true) -- Open to everyone
USING (auth.role() = 'authenticated') -- Any logged-in user sees all rows
Correct pattern:
USING (auth.uid() = user_id) -- User sees only their own rows
Why it matters: The dashboard can show RLS as enabled even when policies are permissive. Two apps in VibeScan's May 2026 early sample exposed Supabase tables to unauthenticated requests.
3. Security headers are configured
What to check: Run a URL scan with VibeScan, or use securityheaders.com on your deployed URL.
Minimum required:
// next.config.js headers()
{ key: "X-Frame-Options", value: "DENY" },
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
{ key: "Strict-Transport-Security", value: "max-age=31536000; includeSubDomains" },
Why it matters: 53 of the first 61 completed VibeScan URL scans lacked the standard HTTP security-header set checked by the scanner. Missing headers leave browsers unable to enforce those protections.
4. Every route that reads user data verifies ownership server-side
What to check: For every API route that returns data, does the server verify that the requesting user owns that data — not just that they are logged in?
Red flag:
// Returns data for any authenticated user
const { data } = await supabase.from('notes').select('*');
Correct:
// Returns only the requesting user's data
const { data } = await supabase
.from('notes')
.select('*')
.eq('user_id', session.user.id);
Why it matters: IDOR lets one user access another user's records by changing an identifier. The fix is server-side ownership verification, not frontend filtering. This check requires authenticated testing and is outside what a passive public-URL scan can prove.
5. Auth logic is not inverted
What to check: Find every route guard or middleware that checks authentication or role. Read the condition carefully.
Common AI-generated mistake:
// This blocks authenticated admins, allows anonymous users
if (user.role !== 'admin') {
return new Response('Forbidden', { status: 403 });
}
Correct:
// This blocks non-admins
if (!user || user.role !== 'admin') {
return new Response('Forbidden', { status: 403 });
}
Why it matters: Inverted auth logic can be syntactically valid and pass linting while doing the opposite of what the developer intended. Confirm it through source review and tests rather than relying on a scanner prevalence claim.
6. No admin or debug routes are publicly accessible
What to check: List every route in your app. Any route that performs admin actions, returns aggregate data, exposes internal state, or was built as scaffolding must require authentication.
Common patterns to look for: /admin, /debug, /internal, /api/admin, any route created during development that was not intended for public use.
Why it matters: A forgotten admin or debug route can expose internal state or privileged actions without authentication. VibeScan can look for public-surface symptoms, but authenticated authorization testing is still required.
7. Dependencies are not critically outdated
What to check: Run npm audit in your project. Or paste your package-lock.json or yarn.lock into VibeScan for CVE matching.
What to act on immediately: Any critical or high severity advisory with a known fix available. Not all vulnerabilities are exploitable in your specific usage, but anything critical with a simple npm update fix should be done before launch.
Why it matters: AI tools recommend packages based on training data that may be months or years old. Some of those packages have since had vulnerabilities disclosed.
8. Rate limiting is on for auth endpoints
What to check: Try hitting your sign-in, sign-up, and password reset endpoints in rapid succession. Does the server rate limit?
Supabase has built-in rate limiting on Auth endpoints — but if you have built custom auth flows or proxy endpoints, those need their own limits.
Why it matters: Missing rate limits enable credential stuffing and magic-link abuse. Verify the behavior against the limits documented by your auth provider and any custom proxy endpoints.
9. Email authentication is configured for your sending domain
What to check: Run the VibeScan email security checker on your domain. Confirm SPF and DMARC are present.
For Resend (the most common transactional email provider for AI-built apps):
- SPF: add
include:_spf.resend.comto your root domain TXT record - DKIM: add the CNAME record Resend provides
- DMARC: add
_dmarcTXT with at minimumv=DMARC1; p=quarantine
Why it matters: Without SPF and DMARC, your transactional emails (OTPs, receipts, password resets) are more likely to land in spam — and your domain can be spoofed to send phishing emails.
10. You have tested the app as a real user, not just as yourself
What to check: Create a second test account. Verify that the second account cannot access the first account's data by modifying IDs in URLs, API requests, or query parameters.
This takes five minutes and catches IDOR, open RLS, and auth bypass issues that automated scans sometimes miss because they require context about your specific data model.
Run the automated checks
VibeScan covers items 1, 3, 7, 9, and parts of 2 and 6 automatically in a 30-second scan. Paste your URL and get results without connecting your repository.
Items 4, 5, 8, and 10 require manual review of your code and app behavior — they involve semantic analysis that no automated scanner fully handles yet.
Sources: PreBreach OWASP Top 10 in AI-Generated Code (Feb 2026); ShipSafe Cursor Security Analysis (Mar 2026); VibeWrench 100-app benchmark (2025–2026); CVE-2025-48757 (Lovable).