SecureStartKit
SecurityFeaturesPricingDocsBlogChangelog
Sign inBuy Now
Home/Security

Security patterns for Next.js, Supabase, and Stripe

16 common weaknesses in a Next.js + Supabase + Stripe SaaS, each with the vulnerable code, the fix, how to spot it in your own codebase, and whether SecureStartKit prevents it by default.

Injection & XSS

  • High · CWE-89
    SQL Injection in Supabase QueriesUser input is interpolated into a .or() or .filter() string, or concatenated into a Postgres function’s dynamic SQL, instead of being passed as a bound value.◐Blast radius limited
  • High · CWE-20
    Unvalidated Server Action InputA Server Action reads FormData fields or typed arguments and passes them directly to a database query, or spreads them with the spread operator, without first running them through a Zod schema.◐Blast radius limited
  • High · CWE-79
    XSS via dangerouslySetInnerHTMLdangerouslySetInnerHTML is set from user-controlled HTML or from Markdown-to-HTML output without first running the string through a sanitizer such as DOMPurify.◐Blast radius limited

Authentication & Access

  • Critical · CWE-285
    Next.js Middleware Auth BypassAuthorization is implemented only in middleware.ts or proxy.ts, with no second check at the data layer or inside the Server Action, route handler, or page component.◐Blast radius limited
  • Medium · CWE-601
    Open Redirect in Auth CallbackAn auth callback or login route redirects to a user-supplied next or redirectTo parameter without checking that it is a same-origin relative path.○Your responsibility
  • High · CWE-287
    Trusting getSession() Instead of getUser()A Server Component, Server Action, or route handler calls supabase.auth.getSession() and uses session.user to decide access, trusting a value read straight from the request cookie.✓Prevented by default

Data Access & RLS

  • High · CWE-639
    IDOR: Missing Ownership CheckA Server Action or route handler reads or writes a record using createAdminClient() with only an id filter and no ownership filter. Because service_role skips Row Level Security, any authenticated user can access any row by supplying an arbitrary id.◐Blast radius limited
  • High · CWE-915
    Mass Assignment in Server ActionsA Server Action builds its update or insert from a spread of the request body, or from a schema that uses passthrough or a record type, instead of writing a fixed set of named columns.◐Blast radius limited
  • Critical · CWE-862
    Missing or Disabled RLS PolicyA table holding user data has RLS disabled, or has a policy whose USING expression is not scoped to the current user (for example USING (true)), allowing the anon or authenticated role to read or modify every row.✓Prevented by default
  • High · CWE-863
    RLS Policy With USING but No WITH CHECKAn INSERT, UPDATE, or FOR ALL policy defines USING but no WITH CHECK, so the resulting row is validated by nothing and a user can set a foreign owner id.○Your responsibility

Secrets & Config

  • Critical · CWE-522
    Exposed Supabase service_role KeyThe service_role key appears in browser DevTools under the Network tab or Sources panel, is readable in your built JavaScript bundle, is committed to a git repository, or is returned inside an API response body.◐Blast radius limited
  • Medium · CWE-693
    Missing Security Headers and CSPThe app sends no Content-Security-Policy and no Permissions-Policy, or ships with none of the baseline headers configured in next.config.ts.◐Blast radius limited

Payments & Webhooks

  • Medium · CWE-294
    Duplicate Stripe Webhook Events (No Idempotency)A Stripe webhook handler performs side effects (insert a purchase, send an email, grant access) without checking whether that event id was already processed, and returns a non-2xx on duplicates.✓Prevented by default
  • High · CWE-472
    Price and Plan Tampering at CheckoutA checkout Server Action passes a client-supplied priceId straight into line_items, or stores a client-supplied product name as the entitlement, instead of resolving both from a server-side allowlist.✓Prevented by default
  • High · CWE-345
    Unverified Stripe Webhook SignatureThe webhook route handler calls req.json() and acts on event.type directly, without calling stripe.webhooks.constructEvent against the raw body and the signing secret in STRIPE_WEBHOOK_SECRET.✓Prevented by default

Abuse & Rate Limiting

  • Medium · CWE-770
    No Rate Limit on Server ActionsA sensitive or expensive Server Action (password reset, magic-link send, AI call, Stripe Checkout creation) runs with no per-IP or per-user rate limit in front of it.◐Blast radius limited
SecureStartKit

The security-first Next.js SaaS template. Auth, payments, and everything you need to launch - with backend-only data access, Zod validation on every input, and built-in optimization for AI coding agents.

Summarize with AI

Product

  • Security
  • Features
  • Pricing
  • FAQ
  • Docs
  • About

Use Cases

  • For Indie Hackers
  • For Solo Developers
  • Fintech SaaS
  • Internal Tools
  • Healthtech SaaS

Free Tools

  • All Tools
  • RLS Policy Generator
  • Security Checklist
  • Security Headers
  • JWT Decoder
  • JWT Generator
  • CORS Config Generator
  • JSON to Zod Converter
  • API Key Generator
  • Stripe Webhook Verifier
  • Stripe Fee Calculator
  • SaaS Pricing Calculator
  • Tech Stack Costs
  • OG Image Preview

Compare

  • All comparisons
  • vs ShipFast
  • vs Makerkit
  • vs Supastarter
  • vs Divjoy
  • vs Nextbase
  • One-time vs subscription

Resources

  • Blog
  • Glossary
  • Security Patterns
  • Changelog
  • Contact
  • Privacy
  • Terms

More from the same maker

  • AppScreenshotStudio
  • QueryScope
  • BookIllustrationAI
  • MyCVCraft
  • StyleMyFade

© 2026 SecureStartKit. All rights reserved.

Built with SecureStartKit