Teardown: Vercel's Official Stripe Template Ships With No Rate Limiting on Checkout - VibeDoctor 
← All Articles 🔬 Teardowns High

Teardown: Vercel's Official Stripe Template Ships With No Rate Limiting on Checkout

We scanned vercel/nextjs-subscription-payments: 93 findings, checkout sessions created with zero rate limiting, and five advisories in the pinned Next.js.

SEC-020 SEC-017

Quick Answer

We ran a full VibeDoctor code scan of vercel/nextjs-subscription-payments, the official Next.js + Stripe + Supabase subscription starter. The report: 93 findings (1 critical, 19 high, 59 medium, 14 low), overall score 70/100. The webhook logic is solid - our Stripe correctness checks stay silent on it, deservedly. But the route that creates checkout and billing-portal sessions has no rate limiting at all, the pinned [email protected] carries five known advisories, and the repo ships zero tests.

Why This Repo Matters

When a vibe coder asks an AI assistant for "Next.js subscriptions with Stripe," the answer is this template's DNA. It is the official starting point, maintained under the Vercel org, and it deserves credit: the webhook in app/api/webhooks/route.ts handles customer.subscription.updated and .deleted, types its renewal objects correctly, and verifies signatures. The renewal bug we found in shadcn's taxonomy is absent here - and our scanner's Stripe object-type and missing-cancellation checks correctly do not fire. Precision matters: a report that cried wolf on the official template would be worthless.

What the template does not give you is everything around the happy path - and that is what clones inherit.

The Scan

One VibeDoctor codebase scan, run on 2026-06-12. Every number below comes from that report.

MetricResult
Overall score70 / 100
Total findings93
Critical1
High19
Medium59
Low14

Finding 1: Checkout Sessions With No Rate Limit (High)

Where: utils/stripe/server.ts, line 89.

The server helper that creates Stripe checkout sessions (and billing-portal sessions) can be invoked with no rate limiting anywhere in the project - no middleware, no limiter dependency, nothing. Every clone of this template ships a route where one scripted user can create Stripe sessions in a tight loop. That is an abuse surface (card-testing rings actively look for exactly this) and a noisy-neighbor problem for your Stripe account long before it is a security headline.

Rate limiting is the kind of thing template authors reasonably leave out - it depends on your infra. But clones do not know that. They ship the absence.

Finding 2: The JWT in the Example Env (Critical, With Honest Context)

Where: .env.local.example, line 4.

Secret detection flags a real JSON Web Token committed in the example env file. Context matters: it is a demo Supabase anon key, the kind that is designed to be public, so as a vulnerability it is a judgment call you can dismiss in one click in the report. But the pattern it teaches is the problem - thousands of cloners learn that tokens belong in committed env files, and the day one of them pastes a service-role key into the same line, it is game over. Any secret scanner in any CI pipeline will also hard-stop on this file forever.

Finding 3: The Pinned Framework Has Five Known Advisories (High)

The template pins [email protected], which now carries five known high-severity advisories (including GHSA-mwv6-3258-q52c and GHSA-q4gf-8mx6-v5v3). This is the quiet tax of template-driven development: the repo was patched-current the day it was published, and every clone since inherits the rot. If your app started here, your lockfile probably still says 14.2.3.

The Rest of the Report

The remaining highs: no React error boundary anywhere in the app (one unhandled render error blanks the whole page), no test directory and a near-zero test ratio, an implicit-any in the same Stripe server helper, and a cluster of accessibility findings (SVGs without titles, a non-null-asserted optional chain in the customer portal form). Fifty-nine mediums round it out - mostly code-quality and config hygiene.

The Takeaway

This is the best-case template - written by experts, webhook done right - and a fresh clone still starts life at 70/100 with an unprotected money route and an aging framework pin. A template gives you the happy path. The audit tells you what the happy path left out, for your specific app, before your users find out.

Built on this template?

A Launch Audit runs this exact report against your app: rate-limit coverage on money routes, webhook correctness, dependency advisories, and a plain-language launch verdict. One-time, per app - no subscription.

GET MY LAUNCH AUDIT →

Diagnose your codebase - free

VibeDoctor checks for SEC-020, SEC-017 and 128 other issues across 15 diagnostic areas - security, performance, code quality, and more.

SCAN MY APP →
← Back to all articles View all 129+ checks →