Skip to main content

ShipSafe

ShipSafe
ShipSafe
ChecklistSecurityVibe Coding

The Vibe Coding Security Checklist (2026): Ship Fast, Stay Safe

A complete security checklist for developers shipping AI-built apps. 20 checks across secrets, auth, injection, XSS, and configuration. Print it, pin it, use it.

5 min read

You built your app with AI. It works. Users can sign up, create data, and do what they need to do. Now you need to make sure it is secure before you ship it.

This checklist covers the 20 most critical security checks for AI-generated applications. It is based on our analysis of hundreds of apps built with Cursor, Lovable, Bolt.new, and other AI tools, cross-referenced with the OWASP Top 10 and the Stanford AI code security research.

Print it. Pin it next to your monitor. Run through it before every deploy.

Secrets Management

Hardcoded secrets are the easiest vulnerability for attackers to exploit and the most common in AI-generated code.

  • 1

    No hardcoded API keys, tokens, or passwords in source code

    Search your codebase for strings matching common key patterns: sk_live_, sk-proj-, SG., ghp_, Bearer, password=. Every secret must come from an environment variable, not a string literal.

    CWE-798: Hard-coded Credentials
  • 2

    No secrets in client-side environment variables

    Variables prefixed with VITE_, NEXT_PUBLIC_, or REACT_APP_ are bundled into client JavaScript and visible to anyone. Only truly public values (Supabase anon key, public API URLs) should use these prefixes.

    CWE-200: Exposure of Sensitive Information
  • 3

    .env is in .gitignore

    Verify that .env, .env.local, and .env.production are listed in your .gitignore file. Run git log --all --full-history -- .env to check if any env files were ever committed. If they were, rotate every secret in them immediately.

  • 4

    Supabase service role key is server-side only

    The service_role key bypasses all Row Level Security. It must never appear in client code. Use it only in Supabase Edge Functions or server-side API routes. The anon key is safe for client use.

    CWE-250: Execution with Unnecessary Privileges

Authentication & Authorization

Broken access control is the #1 vulnerability category in the OWASP Top 10. AI tools get this wrong more than anything else.

  • 5

    Every API route has authentication middleware

    No API endpoint that accesses user data should be callable without a valid session or token. Apply auth middleware at the router level so new routes are protected by default.

    CWE-306: Missing Authentication
  • 6

    Auth conditions are not inverted

    Manually verify that your auth guards redirect/reject when there is NO session (if (!session)) rather than when there IS a session (if (session)). This inversion is found in 31% of Cursor-built apps.

    CWE-863: Incorrect Authorization
  • 7

    Database queries are scoped to the authenticated user

    Every findUnique, update, and delete call should include a userId or organizationId constraint from the session. Never trust a user-supplied ID without verifying ownership. This prevents IDOR attacks.

    CWE-639: Insecure Direct Object Reference
  • 8

    Role checks are enforced server-side, not just in the UI

    Frontend role checks (hiding admin buttons, redirecting non-admins) are for UX only. Every privileged API endpoint must independently verify the user's role from the server-side session.

    CWE-862: Missing Authorization
  • 9

    Supabase RLS is enabled on every table with policies defined

    In the Supabase dashboard, every table storing user data should show 'RLS Enabled'. Each table needs SELECT, INSERT, UPDATE, and DELETE policies scoped to auth.uid(). Tables without RLS are fully accessible to any authenticated user.

  • 10

    Password reset and magic link flows are verified

    Test that password reset tokens expire, cannot be reused, and are invalidated when a new one is generated. Verify that magic links have a short expiry (10-15 minutes) and are single-use.

Injection Prevention

Injection has been in the OWASP Top 10 since its creation. AI tools frequently generate injection-vulnerable code when implementing search, filtering, and dynamic queries.

  • 11

    No string interpolation in SQL queries

    Search for $queryRawUnsafe, string concatenation in queries, or template literals building SQL strings. Use your ORM's query builder or parameterized queries ($queryRaw with tagged templates in Prisma).

    CWE-89: SQL Injection
  • 12

    All user input is validated with a schema library

    Every form submission and API endpoint should validate input with Zod, Yup, or joi. Check for type correctness, length limits, format patterns (email, URL), and allowed values (enums). Validate on both client and server.

    CWE-20: Improper Input Validation
  • 13

    No shell command execution with user input

    Search for exec(), spawn(), or system() calls that include user-supplied data. If shell commands are necessary, use a whitelist of allowed commands and never pass user input directly.

    CWE-78: OS Command Injection

XSS Protection

Cross-Site Scripting allows attackers to execute JavaScript in your users' browsers, stealing sessions, credentials, and data.

  • 14

    No dangerouslySetInnerHTML with user-generated content

    Search for dangerouslySetInnerHTML in your React codebase. If it renders content that users can control (comments, profile bios, messages), it is an XSS vector. Use a sanitization library like DOMPurify if you must render HTML.

    CWE-79: Cross-Site Scripting
  • 15

    Content-Security-Policy header is set

    Add a CSP header that restricts script sources. At minimum: script-src 'self'. This prevents inline script injection even if an XSS vector exists. Test with the browser console for CSP violations before deploying.

  • 16

    User-generated URLs are validated

    If users can provide URLs (profile links, redirect targets, image sources), validate that they start with https:// and do not use javascript: or data: protocols. These can execute arbitrary JavaScript.

    CWE-601: Open Redirect

Configuration & Infrastructure

Security misconfigurations are silent. Your app works perfectly while being completely exposed.

  • 17

    CORS is restricted to your frontend domain

    Search for cors({ origin: "*" }) or Access-Control-Allow-Origin: *. Replace with your specific frontend domain(s). Wildcard CORS allows any website to make authenticated requests to your API.

    CWE-942: Overly Permissive CORS
  • 18

    Rate limiting is enabled on auth and API endpoints

    Apply strict rate limits (5-10 requests/15 min) on login, registration, and password reset. Apply moderate limits (100 req/15 min) on general API routes. Use express-rate-limit for Express or @upstash/ratelimit for serverless.

    CWE-770: Resource Allocation Without Limits
  • 19

    Error responses do not expose stack traces or internal details

    In production, error responses should return generic messages ("Something went wrong") without stack traces, file paths, database table names, or query details. Check your global error handler.

    CWE-209: Error Message Information Leak
  • 20

    Session cookies have secure attributes

    All session cookies must have: httpOnly: true (prevents JS access), secure: true (HTTPS only), sameSite: "lax" or "strict" (prevents CSRF). Check your authentication library configuration.

    CWE-614: Sensitive Cookie Without Secure Flag

Quick Reference: Search Commands

Use these grep commands to quickly check for the most common issues in your codebase:

# Check for hardcoded secrets
grep -rn "sk_live_|sk-proj-|sk_test_|SG.|ghp_" --include="*.ts" --include="*.tsx" --include="*.js"

# Check for service role key in client code
grep -rn "service_role" --include="*.ts" --include="*.tsx" src/

# Check for dangerous HTML rendering
grep -rn "dangerouslySetInnerHTML" --include="*.tsx" --include="*.jsx" src/

# Check for raw SQL queries
grep -rn "queryRawUnsafe|\$queryRaw`" --include="*.ts" --include="*.js" src/

# Check for permissive CORS
grep -rn 'origin.*"\*"|origin.*\*' --include="*.ts" --include="*.js" src/

# Check for missing RLS (Supabase migrations)
grep -rn "CREATE TABLE" --include="*.sql" supabase/migrations/
# Then verify each table has ENABLE ROW LEVEL SECURITY

# Check for exposed env vars
grep -rn "VITE_.*SECRET|VITE_.*KEY|NEXT_PUBLIC_.*SECRET" .env*

Automate This Checklist

Running through 20 items manually before every deploy is tedious and error-prone. That is why we built ShipSafe.

ShipSafe automates detection for 18 of these 20 checklist items. Paste your GitHub URL, and in under two minutes you get a detailed report covering every vulnerability found, its severity, the exact file and line number, and a specific code fix.

The two items that require manual review — verifying auth condition logic and testing password reset flows — are flagged by ShipSafe with guidance on what to look for. Use ShipSafe for automated coverage and reserve your manual review time for the high-judgment security decisions.

Further Reading

This checklist covers the essentials. For deeper dives into specific tools and vulnerability categories, see:

Want to check your own app?

Paste your GitHub URL and get a security report in under 2 minutes. Free scan, no credit card required.

Scan My App Free