The MVP Shortcuts That Turn Into Security Incidents
Most MVP cuts are safe. Five become incidents: no account recovery, no deletion, untested payments, kit secrets, open admin routes. Plus a one-hour pass.
Marc Lou writes some of the clearest advice on shipping fast. In his newsletter “How to build a startup in 24 hours” (Nov 11, 2023), he lists what to skip. One item is “Anything that’s invisible to the customer: Code testing, git branches, new frameworks”. Another is “Anything that doesn’t add direct value to the customer: Forgotten password, dark mode, a professional logo”.
I agree with most of that list. A first version that ships beats a polished one that doesn’t. I work as a CISO and as a fractional vCISO and CAIO for small AI startups, and I read the list a little differently. Most of those cuts can wait. A few of them are where I’d expect a young product’s first security incident to come from.
Below is how I sort them. None of it slows the launch down; the fixes for all five fit in about an hour.
What is safe to defer
Dark mode, a logo, and the polish layer in general. No customer’s data depends on any of it.
Git branches on a one-person project are fine too. Branches coordinate people, and with one person there is nobody to coordinate. Same for new frameworks: skipping the framework you wanted to try is a cost saving, and it has no security effect.
If your skip list stops there, you’re fine. The five below are on the same list, and each one is a product feature that also does a security job.
The five that become incidents
1. No account recovery
Marc Lou’s list puts “Forgotten password” in the skip pile. In his post on building a SaaS micro startup in days (Mar 2, 2024), he lists what he left out of one launch: “There’s no password reset form, invoice preview, or account deletion.”
What breaks: users get locked out. They email you. Now someone has to decide, on the spot, how to prove that the person writing is the account owner. Nobody has designed that check, so it gets improvised in a support inbox: a reply to an email, a manual change to the account’s address. That is how account takeover through the support desk happens. The attacker’s job gets easier: write a convincing email to the person who answers support.
The cheapest fix: a password reset or magic-link flow from the auth library you already use. Most auth libraries ship one. Turning it on and testing it once is a smaller job than the first improvised recovery.
2. No account deletion
The same quote names account deletion as skipped. GDPR Article 17 is the right to erasure: individuals can ask for their personal data to be erased.
What breaks: the first erasure request arrives by email, and someone deletes rows by hand in the production database. That’s an unreviewed write against live data, done by a person under time pressure, in a schema they may not have in their head. It can remove too little and leave the person’s data behind, or remove too much and take other rows with it.
The cheapest fix is a documented manual runbook and a way to find all of a user’s data. The runbook says who handles the request, how to confirm the requester, and what to delete in what order. The finding part matters more than it sounds: if user data lives in your main tables, a log store, an analytics tool, a payment provider and an email service, you need that list written down before the request shows up. A delete button can come later.
3. No tests on the payment path
Skipping tests is on the safe list, and for most of the codebase I agree. Code that renders a settings page can be wrong for a while with little harm.
The payment path is the exception, because it’s the one place a bug moves money. A webhook handler that processes the same event twice, or ignores a failed payment, or grants access on the wrong event, costs you directly, and it costs you in a way customers notice.
The cheapest fix: at least a test for the webhook handler, and a test for the plan-to-entitlement mapping, meaning the code that decides which plan gets which access. Those two cover where payment state turns into permissions. Everything else in the codebase can stay untested for now.
4. Secrets that came with the starter kit
Starter kits are a good way to ship fast. Most come with an example env file, and some come with placeholder values for signing or session secrets so the app boots on first run.
What breaks: a default key or placeholder secret that came with the starter kit stays in place, and anyone else who has used the same starter kit knows it. Live keys committed to the repo are the other half of this. A repo is easy to copy, share, and give access to later.
The cheapest fix has three parts. Rotate anything that came with the starter kit. Keep live keys out of the repo. And use restricted keys where the provider offers them, so a leaked key can do a narrow set of things instead of everything. Stripe’s restricted API keys are the standard example: you pick which resources a key can touch. I go through the larger version of this problem, keys handed to agents and third parties, in the post on AI agent secrets management.
5. Admin routes and debug endpoints left open
You build an admin page to look at users and fix things. You add a debug endpoint to see what the app is doing. Both are useful on day one.
What breaks: they stay reachable after launch, with no authentication, or with a check that was meant to be temporary. An admin route is a list of your customers with edit buttons. A debug endpoint often shows configuration and environment.
The cheapest fix: before launch, list every route in the app, find the admin and debug ones, and put them behind real authentication or remove them from the production build.
The one-hour pass
None of these needs a security team. Here is the pass I’d run the day before launch. The times add up to about an hour, and they’re my own estimates, not measurements.
| Check | What to do | Time |
|---|---|---|
| Account recovery | Turn on the auth library’s reset or magic-link flow. Send yourself one. | 15 min |
| Account deletion | Write the runbook: who handles it, how to confirm the requester, what to delete. List where a user’s data lives. | 15 min |
| Payment path | Add a test for the webhook handler and one for the plan-to-entitlement mapping. | 15 min |
| Starter kit secrets | Rotate every key that came with the starter kit. Search the repo for live keys. Switch to restricted keys where offered. | 10 min |
| Admin and debug routes | List every route. Put admin behind real auth. Remove debug endpoints from production. | 5 min |
If one of those takes much longer than the time listed, write down which one. That’s the part of the app you understand least, and it’s the one to look at next.
Where this sits next to the rest of the work
A shipped MVP with these five covered is still a young product. It has gaps I haven’t listed, and I’m not claiming the pass makes it secure. It closes the five above, which are the ones I’d expect to show up first.
For the security controls themselves, the post on security controls that assume a team covers which to defer and at what headcount. This post is narrower: the product features that look like polish and carry a security job.
If you’re on the other side of this, holding an app someone else built fast, inheriting a vibe-coded app covers what to look at first. The five above are also a fair list of what the previous builder should have done before handing it over.
If you’re an early-stage AI startup and want someone to run this pass with you, or to tell you which of your own cuts are safe, that’s the kind of conversation I have on my consulting page.