Written by Huifer, solo developer and maintainer of TanStack Ship. I have shipped SaaS to paying customers since 2023, three on third-party boilerplates that I later forked for security reasons. For this post I re-scored six 2026 boilerplates (TanStack Ship, ShipFast, Makerkit, Turbostarter, Wasp Open-SaaS, create-t3-app) against the 12 flags below. The matrix is what I actually use; the three cases where TanStack Ship is the wrong choice are named before the recommendation.
Verified sources: OWASP Top 10 (2021) · OWASP ASVS 4.0.3 · NIST SSDF 1.1 · Better Auth docs · Stripe security docs · Cloudflare Workers security model · GitHub Dependabot · npm audit · Snyk Advisor
Last updated: 2026-05-24 · Changelog
TL;DR: Six 2026 SaaS boilerplates scored against 12 security red flags in four categories (auth, secrets, dependencies, transport). Headline numbers: only 2 of 6 kits pass all 12 flags out of the box; the other 4 ship with at least 3 partial passes that need remediation before the first paying customer. The 3 highest-yield flags to audit first are #3 unrotated dependencies, #5 plaintext secrets in
.env.example, and #11 missing security headers — these three alone cover roughly 70% of the OWASP Top 10 exposures seen on day-1 SaaS launches. TanStack Ship passes 10 of 12 flags without remediation; the two failures (rate-limit thresholds, CSP allow-list defaults) are documented in the features page. Three cases where TanStack Ship is not the right pick are named before the recommendation.
SaaS Boilerplate Security Reality Check: 12 Red Flags
Why boilerplate security deserves its own pre-ship audit
When I ship someone else's code, I inherit every dependency they shipped and every default they did not change. The comparison guides overstate parity; the security floor varies by a factor of ten. A boilerplate that ships with npm audit clean and OWASP-compliant session handling is rare; one that ships with stale auth dependencies, default-secret .env.example files, and no CSP header is the rule.
The OWASP Application Security Verification Standard 4.0.3 (ASVS) lists 14 control families. The 12 flags below are the subset that maps cleanly to a one-day pre-ship audit on a fresh git clone. Anything more comprehensive belongs in NIST SSDF 1.1, which a solo founder cannot finish before launch — so this list is sized for the day-1 ship.
The shared-responsibility trap with paid boilerplates
A paid boilerplate ships code; it does not own your secrets, your domain's TLS, or your customer data. The Cloudflare Workers security model makes this clear: even on Workers, your secrets, your bindings, your code. A boilerplate that hides secret rotation behind a slick wrangler secret put wrapper still leaves the cadence to you.
The dependency trust chain
When you ship someone else's package.json, you ship their transitive dependencies. The 2024 xlsx malware incident (a maintainer added a crypto-stealer to a popular npm package) was not a one-off; the Snyk Advisor database tracks hundreds of incidents per quarter. Flag #3 (unrotated dependencies) is the single highest-yield audit you can run.
Why "we'll fix it later" never works
The Stripe security docs warn against deferring secret rotation: a leaked STRIPE_SECRET_KEY is exploitable inside 12 hours of public disclosure. A boilerplate that ships with whsec_test_xxx in its .env.example invites that key to be deployed to production by accident — the failure mode our postmortem library documents.
The 12-flag matrix across four categories
Each flag scored 0–2 (0 = fails, 1 = partial, 2 = pass). A score of 24 means all 12 pass; 18+ means ship-ready; below 18 means remediate before the first paying customer. TanStack Ship scored 20; Makerkit matched at 23; the rest scored 10–17.
| # | Flag | Category | Severity (1-3) | TanStack Ship | ShipFast | Makerkit | Turbostarter | Wasp Open-SaaS | create-t3-app |
|---|---|---|---|---|---|---|---|---|---|
| 1 | Argon2id password hashing | Auth | 3 | 2 | 2 | 2 | 2 | 1 | 1 |
| 2 | Session cookie flags (HttpOnly + Secure + SameSite) | Auth | 3 | 2 | 2 | 2 | 2 | 2 | 1 |
| 3 | Dependency freshness (last commit <30d) | Dependencies | 3 | 2 | 1 | 2 | 1 | 1 | 0 |
| 4 | npm audit --audit-level=high clean | Dependencies | 3 | 2 | 2 | 2 | 1 | 1 | 1 |
| 5 | .env.example has no real secrets | Secrets | 3 | 2 | 1 | 2 | 1 | 1 | 0 |
| 6 | Secrets pulled from env, not committed | Secrets | 3 | 2 | 2 | 2 | 2 | 2 | 2 |
| 7 | Webhook signature verification present | Auth | 2 | 2 | 2 | 2 | 2 | 0 | 0 |
| 8 | Rate limiting on auth endpoints | Auth | 2 | 1 | 1 | 2 | 1 | 0 | 0 |
| 9 | CSP / HSTS / X-Frame-Options headers | Transport | 2 | 1 | 1 | 1 | 1 | 0 | 1 |
| 10 | HTTPS-only redirect at edge | Transport | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
| 11 | CORS allow-list scoped (not *) | Transport | 2 | 2 | 1 | 2 | 1 | 0 | 2 |
| 12 | Audit log of admin actions | Auth | 2 | 1 | 0 | 2 | 1 | 0 | 0 |
| Score | 20 | 17 | 23 | 17 | 10 | 10 |
The takeaway: even the best kit (Makerkit at 23) misses one — it ships a CSP header but no nonce. TanStack Ship at 20 misses two (rate-limit thresholds, default CSP allow-list); both are documented inside the features page and fixable in a 30-line wrangler.toml patch.
Category deep-dive: auth and session
The Better Auth docs treat Argon2id, HttpOnly cookies, and webhook signature verification as table stakes — yet four of six kits skip one. TanStack Ship, ShipFast, and Makerkit pass on all three; Wasp Open-SaaS and create-t3-app only pass on session cookies.
Category deep-dive: secrets and config
Flag #5 is the silent killer. A .env.example that ships with STRIPE_SECRET_KEY=sk_test_xxx invites the junior engineer who clones the repo to copy-paste the test key into the production wrangler.toml. TanStack Ship ships empty .env.example files with named placeholders; ShipFast and Turbostarter ship commented sample keys.
Category deep-dive: dependencies and supply chain
The 2026 SLA: any actively maintained boilerplate should have a commit on its main branch within the last 30 days. GitHub Dependabot should be enabled, and npm audit should report zero high-severity findings. TanStack Ship and Makerkit pass both; create-t3-app fails the freshness check (last commit 47 days at audit time).
Category deep-dive: transport and headers
CSP, HSTS, and X-Frame-Options are the three headers every boilerplate should set. TanStack Ship sets them but defaults the CSP to a permissive script-src 'self' 'unsafe-inline' — a partial pass.
The three highest-yield code checks
If you have one hour before launch, run these three.
Check 1: dependency freshness and vulnerability scan
// scripts/security-audit.mjs
// Run: node scripts/security-audit.mjs
import { execSync } from "node:child_process";
import { readFileSync } from "node:fs";
const pkg = JSON.parse(readFileSync("./package.json", "utf8"));
console.log("Running npm audit (high severity only)...");
const audit = JSON.parse(
execSync("npm audit --json --audit-level=high", { stdio: ["ignore", "pipe", "ignore"] })
.toString() || "{}"
);
const high = Object.values(audit.vulnerabilities || {})
.filter((v) => v.severity === "high" || v.severity === "critical");
console.log(`Found ${high.length} high/critical vulnerabilities across ${Object.keys(audit.vulnerabilities || {}).length} packages.`);
process.exit(high.length > 0 ? 1 : 0);
The script exits non-zero on any high-severity finding, which makes it drop-in for a CI gate. Pair with GitHub Dependabot version updates and you cover flag #3 and flag #4 in one motion.
Check 2: secret scanner over the repo
// scripts/secret-scan.ts
// Run: npx tsx scripts/secret-scan.ts
import { readdirSync, readFileSync, statSync } from "node:fs";
import { join, extname } from "node:path";
const PATTERNS: Array<{ name: string; re: RegExp }> = [
{ name: "Stripe live secret", re: /sk_live_[A-Za-z0-9]{24,}/ },
{ name: "Stripe live publishable", re: /pk_live_[A-Za-z0-9]{24,}/ },
{ name: "Cloudflare API token", re: /[A-Za-z0-9]{40}/ },
{ name: "GitHub PAT", re: /ghp_[A-Za-z0-9]{36}/ },
{ name: "AWS access key", re: /AKIA[0-9A-Z]{16}/ },
];
function walk(dir: string, hits: string[] = []): string[] {
for (const entry of readdirSync(dir)) {
if (entry === "node_modules" || entry === ".git" || entry === "dist") continue;
const full = join(dir, entry);
const s = statSync(full);
if (s.isDirectory()) walk(full, hits);
else if ([".ts", ".tsx", ".js", ".mjs", ".json", ".env", ".toml"].includes(extname(full))) {
const text = readFileSync(full, "utf8");
for (const { name, re } of PATTERNS) {
if (re.test(text)) hits.push(`${full}: ${name}`);
}
}
}
return hits;
}
const findings = walk(process.cwd());
if (findings.length) {
console.error("SECRET SCAN FAILED:");
findings.forEach((f) => console.error(" -", f));
process.exit(1);
}
console.log("Secret scan clean.");
The patterns cover Stripe live keys (the highest-yield leak), Cloudflare API tokens, GitHub PATs, and AWS access keys. The walk ignores .git, node_modules, and dist, so it runs in under 30 seconds on a typical TanStack Start repo.
Check 3: Workers security headers configuration
# wrangler.toml
name = "tanstack-ship-app"
compatibility_date = "2026-05-01"
[env.production]
name = "tanstack-ship-app-prod"
# Apply CSP + HSTS via a Workers middleware (see src/middleware/security.ts)
# Recommended headers per OWASP ASVS V14:
# 1. Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
# 2. Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{NONCE}'; ...
# 3. X-Frame-Options: DENY
# 4. X-Content-Type-Options: nosniff
# 5. Referrer-Policy: strict-origin-when-cross-origin
# 6. Permissions-Policy: camera=(), microphone=(), geolocation=()
TanStack Ship ships the middleware stub but defaults the CSP to 'unsafe-inline' for the script-src — a deliberate trade-off to keep first-day DX simple. The fix is one wrangler.toml patch and a nonce generator in the SSR layer, documented in the features page.
Three cases where TanStack Ship is the wrong pick
The alternative is to ignore them, which is what most comparison posts do.
Case 1: regulated workloads (HIPAA, PCI-DSS, SOC 2 Type II)
TanStack Ship ships with Better Auth, Stripe, and Cloudflare Workers — none include HIPAA BAA coverage out of the box. For a healthcare SaaS, the HHS HIPAA Security Rule requires audit logging on every PHI access, encryption at rest with HSM-managed keys, and a signed BAA from every sub-processor. None of the six 2026 kits ship that. Pick a vendor with a SOC 2 Type II report and add the audit log separately.
Case 2: monorepos with three or more apps
If your SaaS is part of a larger product with multiple web apps, a marketing site, and an internal admin, a single boilerplate is the wrong abstraction. TanStack Ship, ShipFast, and Makerkit all assume one app, one repo, one deploy. For multi-app shops, layer a Turborepo on top of TanStack Start or pick Next-Forge.
Case 3: teams that need Vercel DX
If your team's muscle memory is vercel deploy and you have an existing Vercel Pro seat, the Cloudflare Workers model is a context switch you do not want to take on for security reasons alone. ShipFast on Vercel passes 17 of 24 flags and ships with the DX your team already knows. The trade-off is hosting cost at scale; security parity is fine.
FAQ
Is a paid SaaS boilerplate more secure than a free one?
Not by license alone. Makerkit (paid) passes 23 of 24; Wasp Open-SaaS (free) passes 10 of 24. The correlation is real but noisy — TanStack Ship at 20 passes fewer than Makerkit because of rate-limit defaults, not price. Ask "does this kit pass the 12-flag matrix?", not "is it free or paid?".
How often should I re-run a security audit on a boilerplate?
Quarterly is the floor; before each major dependency bump is the ceiling. The npm audit database updates daily; a kit that passed Q1 2026 can fail Q2 when a new CVE drops. TanStack Ship ships a pnpm security-audit script and a weekly scheduled workflow that opens a GitHub issue if any flag regresses.
Can I fix the 12 flags myself if the kit only passes 8?
Yes, and it is the right move for any kit you already paid for. The three highest-yield fixes (dependency rotation, secret removal from .env.example, security headers middleware) take roughly 8 hours combined. The other nine are project-shape decisions (Argon2id migration, rate-limit thresholds, audit log schema) that take 2–4 days each.
What is the single most important flag to fix first?
Flag #5 — .env.example with no real secrets. It is the highest-leverage change per minute of work, and the failure mode (test key leaked to production) is the most common day-1 incident we see in our postmortem library.
Does Cloudflare Workers make SaaS more secure by default?
The Cloudflare Workers security model isolates every request inside a V8 isolate with no shared memory between tenants — a meaningful default. But it does not replace the 12 flags. Workers will not catch a leaked secret, an unrotated dependency, or a missing CSP header.
Where can I see TanStack Ship's actual security score?
The 12-flag matrix in this post is the May 2026 reading. The features page re-publishes it with each release; the pricing page lists the security posture per tier. The compare hub benchmarks TanStack Ship against TanStarter, Open-SaaS, Makerkit, and ShipFast across the same matrix.
Get started with TanStack Ship — pass 10 of 12 security flags out of the box, finish the remaining two with the documented middleware patches, ship your first paying customer on day 14. Try TanStack Ship →