Skip to content
Back to field notes
ProcessJune 6, 20266 min read

When does an indie app need a penetration test?

Most indie apps do not need a paid penetration test at launch, but a few specific triggers change that. This note gives you the decision so you spend money where it actually reduces risk.

PentestLaunch decisionProcess

When do I need a penetration test, and when do I not

A penetration test is a paid engagement where a human tester actively tries to break your app: chaining flaws, abusing business logic, escalating from one account to another, and proving what an attacker could actually reach. It is not a scan and not a checklist. It costs real money and takes real calendar time, and for most indie apps at first launch it is not the right next step.

So the honest answer to "do I need a pentest before launch" is: usually not yet, but sometimes clearly yes. The deciding factor is not how big your app feels. It is what kind of data and what kind of money flow through it, and how much damage a single attacker could do before you noticed. A todo app with no payments and no other people's data has a very different threat profile than a multi-tenant SaaS holding customer records behind a login.

The mistake is treating a pentest as a generic launch badge you buy to feel safe, or skipping it on an app that genuinely crosses the line. This note gives you the threshold so you can tell which side you are on.

The triggers that cross the threshold

Some categories change the math. If your app falls into one of these, the case for a real penetration test, or at least a manual security review by a human, gets strong. These are launch-decision triggers, not hard rules, but each one means an automated scan is no longer enough on its own.

If none of these apply, you are probably in the majority of indie apps where a focused public-surface scan plus a manual review of your own auth logic covers the realistic risk at launch.

  • Regulated or sensitive data. Health records, financial account data, government identifiers, or anything covered by a regime like HIPAA, PCI DSS, or similar. The cost of a breach here is legal and regulatory, not just reputational, and these regimes often expect documented testing.
  • Payment and money movement. If your app moves funds, stores card-adjacent data, issues refunds, or grants paid entitlements, an attacker who finds a flaw is directly motivated by money. Stripe handles card data when you use Stripe Checkout, but your own server logic around prices, webhooks, and what a paid plan unlocks is yours to get right, and that logic is exactly where business-logic abuse lives.
  • Multi-tenant isolation. The moment one customer's data must be invisible to another customer, you have a tenant-isolation boundary. A single broken authorization check can let tenant A read tenant B's rows. Automated scans rarely catch this, because it requires logging in as two real accounts and comparing what each can reach.
  • Compliance or customer requirements. An enterprise buyer, an investor, or a partner may contractually require a third-party test before they trust you. Here the pentest is a business requirement, not only a security one.
  • High-value or high-trust accounts. Admin panels that can act on every user, anything holding credentials or tokens for other services, or a workflow where one compromised account causes outsized harm.

Why a public scan is not a pentest substitute

It helps to be precise about pentest vs automated scan, because they answer different questions and the gap between them is where people get the decision wrong.

A public-surface scan checks what an outside visitor can reach without credentials: missing security headers, exposed source maps, a readable .env or .git directory, secret-shaped strings in the client bundle, publicly readable storage buckets, open CORS. These are real launch blockers and they are cheap to check repeatedly. But the scan only sees the unauthenticated outside.

A penetration test goes where a scan cannot. A tester logs in, creates multiple accounts, and probes the parts of your app that only make sense with context.

So the relationship is sequential, not either-or. Clean up everything an automated scan and a self-review can catch first, because there is no point paying a human to find your exposed .env file. Then, if your triggers warrant it, a pentest spends its expensive human hours on the authorization and logic questions a scan structurally cannot answer. For more on that division of labor, see the note on public scan vs code review before launch.

  • Authorization across accounts. Authentication asks "are you logged in"; authorization asks "are you allowed to touch this specific record". A scan confirms a route exists; only an account-aware test confirms that account A cannot read account B's data by changing an id in the request.
  • Business-logic abuse. Skipping a payment step, replaying a webhook, escalating a normal user to admin, or bypassing a rate limit through a side path. These are sequences of legitimate-looking requests, not a single malformed one.
  • Chained findings. A pentester combines several low-severity issues into one real impact, which no single automated signal will surface.

What to do before you spend money on a pentest

If you have decided you do need one, do not book it cold. Every hour the tester spends finding obvious public-surface issues is an hour not spent on the deep authorization work you are actually paying for. Prepare first.

What this preparation does not do is replace the test. A self-review reflects your own blind spots back at you; the reason a pentest has value is that an outsider does not share them. Preparation makes the engagement cheaper and sharper, not unnecessary.

  • Run a public-surface scan and fix the blockers it finds: headers, source maps, exposed artifacts, leaked keys, open buckets. Get to a clean result from a fresh browser session.
  • Do a lightweight threat model yourself. List your trust boundaries, your public routes, and the three data flows that would hurt most if abused, and note where auth is enforced on each. The threat modeling for a solo developer note walks through this in about thirty minutes, and its output is exactly the map a tester wants on day one.
  • Manually test your own authorization. Create two accounts and try to read or change one account's data while logged in as the other. If you find a leak yourself, you have just saved the most expensive part of an engagement.
  • Define scope. Decide what is in and out, give the tester a real account, and document the flows that matter (payments, admin, tenant boundaries) so the time goes where the risk is.

Where VibeCodeGuard fits, and what it does not replace

VibeCodeGuard's Launch Check is the right first step on this path, not the test itself. It scans your public URL from a clean session and flags the public-surface issues: missing or weak security headers, exposed source maps, reachable build and deploy artifacts, secret-shaped strings in the client bundle, publicly readable buckets and endpoints, and open CORS, each with severity and fix direction. Running it before a pentest clears the cheap findings so the engagement focuses on harder questions. Running it on its own is the sensible baseline for an app that does not cross any of the triggers above.

It does not pentest your app, and it is honest about that boundary. Launch Check does not log in, does not compare what two accounts can reach, does not verify authorization across records, and does not probe business logic like payment flows, webhook handling, or entitlement enforcement. Those are the exact questions a penetration test exists to answer, and they need a human and account access that a public-surface scan structurally does not have.

Next step: decide which side of the threshold you are on using the triggers above. If none apply, run a focused Launch Check before sharing the URL publicly and pair it with a self-review of your auth logic. If one or more apply, do that preparation first, then budget for a real penetration test scoped to the flows that carry your actual risk.

A clean Launch Check tells you the unauthenticated outside of your app looks clean. It does not tell you that tenant isolation holds, that authorization is enforced on every record, or that your payment logic cannot be abused. If your app touches regulated data, money, or multi-tenant boundaries, treat the clean scan as the floor, not the finish line.

> launch check

Scan the public surface before launch.

Get severity, evidence, and practical fix guidance for the checks VibeCodeGuard can run from the outside.