We Audited 17 Open-Source SaaS Starters
Every one that takes payment webhooks verifies the signature. Only 3 of 14 skip duplicate deliveries, and 1 of 17 sets a Content-Security-Policy.
The short answer: open-source SaaS starters get the obvious security step right: all 14 that receive payment webhooks verify the signature. The weak spot is what happens next. Stripe states that it can deliver the same event more than once, and only 3 of 14 starters record which events they have already processed. The other 11 are safe today only because their handlers overwrite subscription state; add a welcome email, credits or provisioning to that handler and a duplicate delivery runs it twice.
- 14/14verify webhook signatures
- 3/14skip duplicate webhook deliveries
- 7/17rate-limit sign-in or API routes
- 1/17set a Content-Security-Policy
- 6/17ship no automated tests
- 2/17automate dependency updates
Disclosure: we sell LaunchSaaS, a paid boilerplate. It is not in this table because its code is private and readers could not check our verdicts on it. Every verdict below links to the exact line we read, so you can check ours on everyone else.
Results by starter
Each cell links to the source line behind the verdict, at the commit we audited. Hover a cell for the reasoning. "Partial" for duplicates means the handler is safe to repeat as written but does not detect repeats; "n/a" means the starter syncs billing without webhooks.
| Starter | Signature | Duplicates | Rate limit | Tests | CSP | Dep. bot |
|---|---|---|---|---|---|---|
| apptension/saas-boilerplate Django + React · Stripe (via dj-stripe 2.8.1) |
Yes | Yes | Yes | 258 (CI) | No | No |
| boxyhq/saas-starter-kit Next.js · Stripe |
Yes | Partial | Partial | 8 (CI) | Partial | Yes |
| coremvp/Hikari Next.js · Stripe |
Yes | Partial | No | 5 | No | No |
| electrikhq/electrik Laravel · Stripe (via Laravel Cashier) |
Yes | Partial | Yes | 2 (CI) | No | No |
| eriktaveras/django-saas-boilerplate Django · Stripe |
Yes | Partial | Yes | 4 | Yes | No |
| ernestofgonzalez/djangorocket Django · Stripe |
Yes | Partial | No | 3 (CI) | No | No |
| fogbender/b2b-saaskit Astro + React · Stripe |
n/a | n/a | Partial | 0 | No | No |
| joachimchauvet/modernstack-saas Next.js + Convex · Autumn (hosted billing layer on Stripe) |
n/a | n/a | Yes | 1 | No | No |
| KolbySisk/next-supabase-stripe-starter Next.js + Supabase · Stripe |
Yes | Partial | No | 0 | No | No |
| mickasmt/next-saas-stripe-starter Next.js · Stripe (via @better-auth/stripe plugin) |
Yes | Partial | Yes | 0 | No | No |
| nextacular/nextacular Next.js · Stripe |
Yes | Partial | No | 0 | No | No |
| nextify-limited/saasfly Next.js · Stripe |
Yes | Partial | No | 0 | No | No |
| nextjs/saas-starter Next.js · Stripe |
Yes | Partial | No | 0 | No | No |
| scosman/CMSaasStarter SvelteKit + Supabase · Stripe (no webhooks; live API lookup) |
n/a | n/a | No | 3 (CI) | No | No |
| thedevdojo/wave Laravel · Stripe and Paddle |
Yes | Yes | Yes | 23 (CI) | No | No |
| wasp-lang/open-saas Wasp (React + Node) · Stripe (default), Lemon Squeezy and Polar alternatives |
Yes | Yes | No | 4 (CI) | No | No |
| XCO-Agency/Laravel-SAAS-Starter Laravel · Stripe (Laravel Cashier) |
Yes | Partial | Yes | 247 (CI) | No | Yes |
The raw data, with the evidence for every verdict, is available as JSON (CC BY 4.0).
Why duplicate webhook deliveries matter
Payment providers retry a webhook when your endpoint is slow or returns an error, and Stripe's documentation says an endpoint can receive the same event more than once. A handler that only writes "this subscription is now active" is harmless to repeat. A handler that grants credits, sends a receipt, invites someone to a repository or creates an account is not. The fix is small: store each processed event id under a unique constraint, and skip events you have already seen. Open SaaS, Wave and Apptension's boilerplate (through dj-stripe) do this.
Rate limiting and security headers
7 of 17 starters rate-limit sign-in or API routes in their own code. The Laravel and Django starters mostly get it from the framework (login throttles, allauth or DRF throttles); most Next.js starters have none. Starters on hosted auth such as Supabase may get limits from the provider, which this audit does not count because it is outside the repository. Only 1 of 17 sets a Content-Security-Policy, the browser-side guard against injected scripts.
Method
- Selection: popular open-source SaaS starters on GitHub (100+ stars, pushed within the last 18 months, not archived) that ship billing in the repository. Searched 2026-10-09.
- Reading, not running: each repository was cloned at a fixed commit and read. Nothing was installed or executed. Every verdict cites a file and line.
- Library defaults count when the library is a declared dependency and its default does the job (for example dj-stripe storing events by id, or Laravel Cashier verifying signatures when the webhook secret is set).
- Test files are counted by file, not by test case, and "(CI)" means a workflow in the repository runs them.
Limitations
- This is a static reading of public code at one commit. Repositories change; a verdict can be out of date the day after.
- It checks for the presence of a safeguard, not its quality. A starter with rate limiting on one route scores the same as one with it everywhere.
- Behaviour that lives in hosting or managed services (Supabase auth limits, platform firewalls, Wasp's server defaults) is outside the repository and not counted.
- Paid starters, including ours, are not included: their code is not public.
- Maintainers who think a verdict is wrong can email support@launchsaas.dev; corrections are published with the date.
Not scored
- shadcn-ui/taxonomy: Archived; its README says it does not reflect current best practices and is not for production.
- async-labs/saas: Companion code for a book, not a maintained product.
- makerkit/nextjs-saas-starter-kit-lite: Billing ships in the paid MakerKit kit, not in this repository.
- bullet-train-co/bullet_train: Billing ships in a paid add-on, not in this repository.
- ixartz/SaaS-Boilerplate: Billing ships in paid tiers, not in this repository.
Frequently Asked Questions
Do open-source SaaS starters verify Stripe webhook signatures?
Yes. All 14 starters in this audit that receive payment webhooks verify the signature, either directly (Stripe constructEvent or an HMAC check) or through a library that does it by default, such as dj-stripe or Laravel Cashier.
Do SaaS starters handle duplicate Stripe webhook deliveries?
Only 3 of 14 explicitly record processed event ids and skip repeats. The other 11 rely on handlers that happen to be safe to run twice, usually because they only overwrite subscription state. That stops being true once you add emails, credits or provisioning to the handler.
Which SaaS starters set a Content-Security-Policy?
1 of 17. A CSP is the main browser-side defence against injected scripts, and most starters leave it to you.
How was this audit done?
We read each repository at a fixed commit, without installing or running it, and recorded a verdict for each check with a link to the exact line. Library defaults count when the library is a declared dependency and its default does the job.
Production-ready from day one
Skip re-solving these. Start from code that already has.
13 production packages with 200+ tests of their own, extracted from apps used by 13,000+ people (2,335 tests in those apps). One-time payment, lifetime access.
Get Instant Access - $99