You opened Cursor, described the product, and by the end of the afternoon you had login, a dashboard, and billing running. The demo works. Customers sign up. And that is exactly the problem: the demo works, but it never exercises the flows where the money and the data live.
Vibe coding is the name we stuck on this way of building in 2026. You describe intent, the AI writes the code, you accept the diff. Claude Code, Cursor, Copilot, v0, Lovable, and Replit shrank the distance between "idea" and "SaaS in production" more than ever. That is genuinely good. What nobody attached to it is the bill that comes later: the security debt the AI quietly piles up while you celebrate the speed.
The debt that never shows up in the demo
AI-generated code is not insecure out of malice. It is insecure out of optimization. The model optimizes to make the happy path work. It hands you the route that saves the record, but not necessarily the check that this user is allowed to save that record. It hands you the file upload, but not the size cap or the type validation. It hands you the webhook that receives the payment event, but not the signature verification that proves the event actually came from Stripe.
None of that breaks the demo. All of it breaks in the incident.
And the incident in 2026 is not hypothetical. The npm supply chain turned into a minefield. In March, a compromised version of axios, one of the most downloaded HTTP libraries in the ecosystem, was used to deliver a RAT (remote access trojan). In June, the Mastra case dumped roughly 140 malicious packages into the registry at once. Typosquats (packages named almost exactly like the real one) keep stealing secrets out of CI/CD pipelines when someone installs the wrong package because of a single character. The AI agent that "fixes the import for you" does not know the difference between the legitimate package and the malicious twin. It installs whatever compiles.
The RET thesis is simple: AI lets anyone ship SaaS fast, but the sensitive flows (login, permissions, billing, per-customer data, uploads, admin) are still exactly where the leak and the loss happen. Speed does not remove those flows. It just makes you walk past them without looking.
Why the sensitive flows are different
A layout bug you can see. A button that does not click you can see. An authorization flaw you cannot see, because from your seat, logged in as yourself, everything works. The hole only shows up when someone else, with a different id, calls the same route and receives data that is not theirs.
That is the vibe coding pattern: the developer tests as the owner, the AI optimizes the common path, and the adversarial path (the curious customer, the automated script, the attacker) never enters the test. That is why AI-built SaaS security is not about distrusting the AI. It is about knowing which flows deserve a second human pass before you scale.
The checklist before you grow
Run this before you open the doors to more users. It is not a database audit, it is foundation hygiene. Each item comes with a one-line reason.
- AuthZ on the actual route, not somewhere in the middle. Every route that reads or writes a customer's data must check that the logged-in user is entitled to that resource, right there on the route, because being logged in is not the same as being allowed.
- Tenant isolation in every query. Every query that returns customer data has to filter by owner, otherwise customer A lists customer B's records with a single swapped
id. - Secrets in a vault, not in an exposed
env. API keys, tokens, and connection strings live in a secrets manager, never committed and never printed to a log, because a secret in the repo is a leaked secret. - Committed
lockfileandnpm ciin the build. Pin exact versions and install from the lock, becausenpm installon the server can pull a freshly compromised version between your test and your deploy. - Dependency review before you install. Check the exact name, the download count, and the package date before adding it, because typosquats and hijacked packages get in precisely through the rush of
add. - Input validation that parses, not just checks. Turn raw input into a domain type at the boundary (with
zodor equivalent) and trust the type afterwards, because validating and then still using the raw data leaves the gap wide open. - Rate limiting on public endpoints. Login, password reset, and any expensive route need limits per IP and per account, because without them a script runs brute force and runs up your cloud bill.
- Signed and verified webhooks. Every payment or third-party webhook must have its signature verified before acting, because otherwise anyone POSTs a request pretending to be Stripe and activates a subscription for free.
- Error states that do not leak. User-facing error messages must not return a stack trace, a query, or a file path, because the attacker reads the error to map your system.
- Security headers configured.
Content-Security-Policy,HSTS,X-Content-Type-Optionsand friends close whole classes of attack for free, because the browser becomes your ally once you tell it what to block. - Uploads with a size cap and type check. Every upload needs a size limit, real type validation (not just the extension), and storage outside the servable root, because a free-for-all upload is remote execution waiting to happen.
- Money and data flows get a human review. Billing, plan changes, account deletion, and data export go through a human eye on the diff, because those are the flows where a silent bug turns into a chargeback, a leak, or a lawsuit.
- Logs without sensitive data. Do not dump passwords, tokens, PII, or card numbers into logs, because logs are copied, indexed, and read by plenty of people who should never see any of it.
- New dependencies only when needed. Every package is new attack surface; prefer what the language or the framework already gives you before pulling one more dependency from the registry.
How to use this without stopping the shipping
You do not need to do all fourteen at once. The point of the checklist is the priority order. If you only have one afternoon, start with the three that hurt the most when they fail: authorization on the route, tenant isolation, and signed webhooks. Those three protect money and other customers' data, which is the kind of failure that becomes a headline instead of just a ticket.
AI is still the best thing that ever happened to product speed. It does not turn against you. What turns against you is treating generated code as finished just because the demo passed. Let the AI write the flows. Do the second human pass on the ones that touch money, permissions, and customer data. It is cheap now and brutally expensive later.
Vibe coding's security debt never shows up in the demo, it shows up in the incident.




