Your first customer's data is worth more than $1,000 of legal exposure. The math doesn't work in your favor: the cost of a small breach disclosure — emails, notifications, the credibility hit, the time you don't get back — is multiple orders of magnitude above the cost of an hour spent verifying that the obvious bugs aren't in your app. Spend the hour. Not the four figures.
This is the 2026 version of the indie/vibe-coder security checklist. It's not OWASP Top 10 — that's a list for engineers building enterprise web apps. This is a list for someone who shipped an MVP this week with Cursor or v0, who has zero security training, and whose threat model is "the internet" plus "the first few hundred customers." Different list, different bugs, different fixes.
If you check all 17 items, you've cleared the bar that distinguishes "would get popped on Product Hunt day" from "will probably survive your first paying cohort." Not perfect. Not enterprise-grade. Real-world good enough.
Why this list isn't the OWASP Top 10
OWASP is correct. It's also calibrated for codebases that humans wrote start to finish. The bug distribution of vibe-coded MVPs in 2026 is different in three material ways:
- BOLA dominates. In hand-written code, broken auth and injection bugs are common. In AI-generated code, the same classes exist but BOLA / IDOR (cross-tenant data access) is the runaway leader because LLMs predict the WHERE clause that exists in their training data, not the WHERE clause your specific app needs.
- Misconfiguration > code defects. Most indie-MVP findings aren't bugs in the code — they're defaults that were never tightened. Supabase RLS off. Cloudflare cache rules wrong. CORS wide open. Auth tokens with no expiry. The fix is rarely "patch the code"; it's "change the setting."
- Secrets in bundles. Modern frameworks blur the client/server boundary, and AI assistants don't always honor it. Secret leakage to client bundles is a top-three finding now.
So the list below is reordered around what AI assistants actually generate, what indie ops actually leave default, and what a bored attacker tries first against an unknown SaaS.
The 17 items in 3 tiers
Each item has a tier (how long it takes to verify and fix), a check, and a fix. Run the 5-minute tier today. The 1-hour tier tomorrow. The 1-day tier before your next launch.
Tier 1: Fixes in 5 minutes
1. Every API route has an explicit auth decision
Check: curl -s -o /dev/null -w "%{http_code}\n" https://app.com/api/<each-route> without a session. Anything that returns 200 must be a public-by-design endpoint. If it's not, fix.
Fix: Add the auth check at the top of the handler. Better: middleware that protects /api/* by default with an explicit allowlist.
2. Cross-user data access returns 403/404
Check: Two test accounts; request account A's resource ID using account B's session. Must not return A's data.
Fix: The WHERE clause includes { ownerId: session.user.id } on every owned-data query. This single fix prevents most BOLA, including the bug class behind CVE-2025-48757 (170+ Lovable-generated apps disclosed in 2025).
3. Supabase RLS is on for every user-data table
Check: curl "$SUPA_URL/rest/v1/users?select=*" -H "apikey: $ANON_KEY". Returns user rows? RLS is off.
Fix: ALTER TABLE users ENABLE ROW LEVEL SECURITY; then add a policy. Repeat for every table the anon key can touch. 83% of exposed Supabase databases fail this check.
4. The build doesn't ship server secrets
Check: npm run build && grep -rE "sk_(test|live)_|service_role|PRIVATE_KEY|xoxp-|ghp_" .next/static/ public/
Fix: Add import 'server-only' to any module that uses a secret. The build will fail at the import point if it ends up in a client component.
5. CSP header is set
Check: curl -sI https://app.com | grep -i content-security-policy. Empty? You have no XSS containment.
Fix: Start with default-src 'self'; script-src 'self' 'unsafe-inline'; img-src 'self' data: https:; and tighten over time. Imperfect CSP beats no CSP.
6. HTTPS is forced and HSTS is on
Check: curl -sI https://app.com | grep -i strict-transport
Fix: Most hosting platforms (Vercel, Netlify, Cloudflare) have a one-toggle for "Always use HTTPS" plus HSTS. Flip it.
7. Webhook endpoints verify signatures
Check: Send a forged payload to /api/webhooks/stripe or your equivalent. Does the route 200 anyway? If yes, signature verification is missing.
Fix: Stripe, GitHub, Polar, Resend — every one of them gives you a signing secret and an example signature-verification snippet. Paste it in. Until it's in, your webhook is a remote write endpoint with no auth.
Tier 2: Fixes in 1 hour
8. Rate limits on auth endpoints
Check: 20 wrong passwords in a row against /api/auth/signin. All 200/401? No rate limit.
Fix: Upstash Ratelimit with sliding window (5 attempts / 15 minutes). Free tier is enough for indie traffic. Apply to signin, signup, password reset, and any AI inference endpoint that costs money to run.
9. JWT algorithm is locked down
Check: Decode your JWT header. alg: none is catastrophic. alg: RS256 with an exposed JWKS that allows downgrade to HS256 is the classic confusion attack.
Fix: Always pass algorithms: ['HS256'] (or your chosen single algorithm) to jwt.verify. Reject everything else.
10. Admin endpoints check a role, not just a session
Check: Regular user session, request /api/admin/*. 403? Good. 200? Critical.
Fix: if (session.user.role !== 'admin') return 403. Don't rely on the UI not linking to admin routes.
11. CORS doesn't pair wildcard with credentials
Check: curl -sI -H "Origin: https://evil.com" https://app.com/api/anything. If you see Access-Control-Allow-Origin: * together with Allow-Credentials: true, fix immediately.
Fix: Allowlist your real origins. Echo the request origin back only if it's on the allowlist.
12. File uploads have content-type and extension whitelists
Check: Upload x.html renamed to x.png. Does your storage serve it back as HTML? If yes, stored-XSS surface exists.
Fix: Validate extension AND content-type. Strip executable extensions. Serve uploads from a subdomain with a strict Content-Type response header.
13. Dependencies are pinned and audited
Check: npm audit --omit=dev. Critical or high? Fix.
Fix: Use a lockfile. Set up Dependabot or Renovate. Subscribe to GitHub Security Advisories for the language you ship in. The xz-utils supply-chain backdoor (CVE-2024-3094) was the wake-up call that pinning isn't optional anymore.
Tier 3: Fixes in 1 day
14. Container/runtime patching policy
Check: When was your last image rebuild? If you run Docker and your base image is older than 30 days, you're potentially vulnerable to known runtime escapes like CVE-2024-21626 (runc "Leaky Vessels").
Fix: Rebuild on a cadence. Use distroless or minimal base images. Subscribe to Docker / runc security advisories.
15. Self-hosted AI tooling is patched
Check: Are you running Ollama, Hugging Face's transformers, vLLM, or similar locally? Are they up to date? The Ollama path-traversal-to-RCE bug (CVE-2024-37032) hit thousands of exposed instances; if your AI tooling listens on 0.0.0.0, you have a public RCE surface unless you've patched and firewalled.
Fix: Bind to localhost. Put a reverse proxy with auth in front. Patch on every release. Don't expose model-serving ports to the internet without auth.
16. Backups exist, are encrypted, and have been restored
Check: Do you have a recent restore-from-backup test? "We have backups" without "we tested restore" is the same as "we don't have backups."
Fix: Automate daily backups. Encrypt them. Run a restore-from-scratch test quarterly. Document the runbook.
17. There's an incident response plan
Check: If you got a credible "your data is on a forum" email tomorrow, what would you do in the first hour?
Fix: A one-page runbook with: who to call, how to rotate the most critical credentials, how to put the app in read-only mode, what to tell customers. The point isn't a perfect plan — it's having any plan that isn't "panic."
When to escalate to a pro
Most indie founders can clear all 17 items in a focused day. Where that breaks down is when you have findings that don't fit the checklist — the chained vulnerabilities, the protocol-level oddities, the parts of your stack that aren't in the standard playbook. That's the work a pro is for.
If you want the structured version of items 1-12, the free pre-launch checklist walks through the verification commands with curl outputs you can paste. The headers scan takes 60 seconds and verifies items 5, 6, and 11 automatically. The sample report shows what a full engagement produces beyond the checklist — the chained findings, the re-test proof, the PoC repositories you can hand a developer.
If your app is going to handle customer money, customer messages, or anyone's regulated data, the rigor that a structured engagement adds is worth it. Sable's engagements use the same scans you'd run yourself, plus the manual review that catches what scans don't, plus a re-test after fixes — the bit that turns "we think it's patched" into "we have proof it's patched."
FAQ
I'm pre-revenue. Do I still need to do this?
Yes, but proportionally. Tier 1 is a one-hour sprint and covers the bugs that cause public disclosure incidents. Skipping it is the false economy. Tier 2 and Tier 3 can wait until you have paying customers; Tier 1 cannot wait until your first user.
My app is internal-only / behind Tailscale. Does this still apply?
Most of it, yes. Tailscale removes the "open internet" threat model but doesn't remove the "compromised laptop on your tailnet" threat model, which is realistic. Items 1-4, 7, 9, 10 all still apply. Items 5, 6, 11 are less critical for an internal-only deployment.
Do these checks apply to mobile apps?
The backend checks (1, 2, 3, 7, 8, 10, 13) apply identically — mobile apps hit the same API. The browser-specific items (5, 6, 11, 12) apply to the web companion or admin app. Add three mobile-specific items: certificate pinning, secure storage of refresh tokens, and obfuscation/integrity checks if you handle payments client-side.
Can I automate the whole list?
Most of it. Items 1-7 can be scripted. Items 8-13 can be partially automated. Items 14-17 are operational and need a human to decide. The Sable agent runs the automatable subset; the rest is a checklist your team owns.
How often do I re-run the checklist?
Before every meaningful release, and at minimum quarterly. Every time you ship a new API route, items 1, 2, 7, 10 need re-verification. Every time you change Supabase schema, item 3. Every time you bump a dependency or rebuild a container, items 13, 14.
One worked example: the timing
Here's a realistic schedule for an indie founder who got serious about this checklist last Friday and shipped to paying customers the following Monday.
Friday evening, 90 minutes. Tier 1, all seven items. The route enumeration scan finds two unprotected admin routes. The BOLA check finds the standard missing-ownership clause in three places. The Supabase RLS check finds one table — the audit log — left open by default. The bundle grep is clean. CSP and HSTS are added in five lines of next.config.ts. Stripe webhook signature verification was already in place from the boilerplate but the Polar webhook wasn't; a 15-minute fix. Total: seven real findings, all fixed in under two hours, including the most likely "I got popped in week one" bugs.
Saturday, 75 minutes. Tier 2. Rate limits added with Upstash. JWT algorithms list-locked. The one admin route discovered yesterday gets a role check. CORS verified. File uploads pinned to image content-types only. npm audit surfaces one high; bumped. The 17 hours of post-incident work that would have followed an unaddressed weekend launch is not happening.
Sunday, 4 hours, then ongoing. Tier 3. Docker images rebuilt against current base. The locally-hosted Ollama bound to localhost behind a Tailscale-only reverse proxy. First backup tested with a real restore-from-empty run. Incident plan written on one Notion page and shared with the co-founder.
Monday. Public launch. The first scraper hits within ten minutes. The Cloudflare WAF rule from the rate-limit work catches it. The disclosure email never arrives.
That's the version of the checklist that actually happens — not a theoretical exercise, but the weekend you spend before the launch you've been planning for three months. Seventeen items. Three tiers. Done.
Seventeen items. Three tiers. One hour for the most important seven. Run it before your first $1K customer trusts you with their data — because the second they do, the cost of every item on this list flips from "an afternoon" to "a four-figure disclosure email." Spend the hour.