▸ Security Checklist · 2025

SaaS Security Checklist

TL;DR

A production SaaS product needs security controls across 7 layers: authentication, database, API, infrastructure, billing, monitoring, and compliance. The six controls that must be in place before any user signs up: httpOnly JWT cookies, RLS on all tenant tables, Zod input validation, Stripe webhook verification, auth rate limiting, and HTTPS with HSTS.

Security issues found after launch with real user data cost 10–100× more to fix than the same issues found before launch. This checklist is run before every 4Byte SaaS goes live.

Controls:50+
Layers:7
Last updated:2025
By:4Byte Agency
50+Controls
Security controls across 7 layers in this checklist
82%of Breaches
Involve a human element — phishing, stolen credentials, or misuse
$4.5MAvg Cost
Of a SaaS data breach in 2024 (IBM Security Report)
Day 1Required
RLS, httpOnly cookies, and HTTPS — non-negotiable from launch

▸ Critical Controls

Six controls that must be in place before any user signs up

Every other security control is important — but these six are the ones where missing them causes immediate, exploitable vulnerabilities with real-world consequences.

!
Critical

httpOnly cookies for JWT storage

localStorage is accessible to JavaScript — one XSS bug exposes every user's session token. httpOnly cookies are completely inaccessible to scripts.

PreventsAccount takeover via XSS
!
Critical

RLS on every tenant table

Application-layer scoping has bugs. RLS is the database-level guarantee that no bug in your API code can ever expose one tenant's data to another.

PreventsCross-tenant data breach
!
Critical

Zod input validation on all API routes

Unvalidated input is the root cause of SQL injection, prototype pollution, and unexpected application behaviour. Validate before any database operation.

PreventsInjection attacks, data corruption
!
Critical

Stripe webhook signature verification

Without verification, anyone can send fake payment success events to your webhook endpoint and fraudulently upgrade their account.

PreventsFraudulent subscription access
!
Critical

Rate limiting on auth endpoints

Unprotected login and signup endpoints can be used for credential stuffing, brute force attacks, and email bombing at scale.

PreventsBrute force, credential stuffing
!
Critical

HTTPS with HSTS header

HTTP exposes all data in transit including session tokens. HSTS prevents browsers from ever connecting over HTTP even if the user types it manually.

PreventsMan-in-the-middle, token theft

▸ Full Security Checklist

50+ security controls across seven layers

This is the complete security checklist 4Byte Agency runs before every SaaS product goes live. Controls marked Critical must be in place before the first user signs up.

01
🔐

Authentication Security

Critical
JWT tokens stored in httpOnly, Secure, SameSite=Lax cookies — never localStorageCritical
Access token expiry ≤ 60 minutes with automatic refresh token rotationCritical
Email verification required before product access is grantedCritical
Rate limiting on login: 10 attempts per IP per 15 minutesCritical
Rate limiting on signup, magic link, and password reset endpointsCritical
OAuth flows use PKCE — not the implicit grant flowCritical
Password minimum 8 characters with common password dictionary check
TOTP-based MFA available for all users, enforced for owner and admin roles in enterprise tier
Session invalidated immediately on password change or role elevationCritical
Generic error messages on auth failures — never reveal whether an email exists
02
🗄️

Database & Data Security

Critical
Row-level security (RLS) enabled on every table containing tenant dataCritical
SELECT RLS policy: users can only read rows belonging to their own organisationCritical
INSERT/UPDATE/DELETE RLS policies: role-checked before any write operationCritical
Cross-tenant data leakage tested explicitly — attempt access from a different org sessionCritical
No raw SQL string concatenation — use parameterised queries via Prisma ORMCritical
Service-role Supabase key never exposed to the client or used in frontend codeCritical
Sensitive data (API keys, tokens) stored encrypted, not as plain textCritical
Database backups automated with at least 7-day retention
No PII stored in application logs or error tracking tools (Sentry)
Soft-delete on user data — no permanent deletion without explicit retention policy
03
⚙️

API & Application Security

Critical
All API inputs validated with Zod schema before any database operationCritical
Role-based authorisation checked at API middleware layer — not only in UICritical
Organisation scoping enforced in every query — no cross-tenant data access possible via APICritical
API rate limiting: 100 req/min per authenticated token, 10 req/min per IP for public routesCritical
CORS policy restricted to known frontend origins — never wildcard (*) in productionCritical
No sensitive data in URL parameters or query strings — use request body or headers
API error responses return generic messages — no stack traces or internal paths in production
Content-Type header validated on all POST/PUT/PATCH endpoints
Idempotency keys enforced on payment and subscription-modifying endpoints
Structured logging with request IDs for all API calls — no PII in logs
04
🌐

Infrastructure & Network Security

High
HTTPS enforced on all routes — HTTP requests redirect to HTTPS automaticallyCritical
HSTS (Strict-Transport-Security) header with minimum 1-year max-ageCritical
Content-Security-Policy (CSP) header configured to prevent XSS injectionCritical
X-Frame-Options: DENY or SAMEORIGIN to prevent clickjacking
X-Content-Type-Options: nosniff to prevent MIME-type sniffing
Referrer-Policy: strict-origin-when-cross-origin
No sensitive API keys in client-side JavaScript bundlesCritical
Environment variables separated per environment: dev, staging, productionCritical
Production environment variables accessible only to authorised team membersCritical
Dependencies scanned for known vulnerabilities in CI/CD pipeline (npm audit / Snyk)
05
💳

Billing & Payment Security

Critical
Stripe webhook signatures verified using stripe.webhooks.constructEvent() on every eventCritical
Subscription state updated only via webhook handlers — never from frontend redirect URLsCritical
Stripe secret key stored server-side only — never in client-side code or public env varsCritical
Card data never touches your servers — Stripe Checkout or Stripe Elements handles collectionCritical
Webhook handler is idempotent — safe to process duplicate events without side effectsCritical
Admin billing overrides (plan changes, trial extensions) logged to audit_logs table
Stripe webhook endpoint restricted to Stripe IP ranges (optional, defence-in-depth)
Test mode and live mode Stripe keys clearly separated — test keys only in non-production
06
📡

Monitoring & Incident Response

High
Error monitoring via Sentry with source maps in production (without exposing source)Critical
Uptime monitoring with < 1-minute check interval and alert on downtimeCritical
Alerting configured for error rate spikes, slow query alerts, and auth failure burstsCritical
Audit log of all admin actions — immutable, append-only, queryableCritical
Failed authentication attempts logged with IP and timestamp (without storing passwords)
Dependency vulnerability alerts enabled (GitHub Dependabot or Snyk)
Database query performance monitoring — alert on queries exceeding 500ms
Defined incident response process — who to contact, how to revoke access, how to notify users
07
📋

Compliance & Privacy

Medium
Privacy Policy published and linked from marketing site and product signup pageCritical
Terms of Service published and accepted during signup (checkbox or click-wrap)Critical
Cookie consent banner if using analytics or tracking cookies (required for EU users)
Data Processing Agreement (DPA) available for B2B customers on request
User data export functionality — export all personal data for a user on request (GDPR Art. 20)
Account deletion deletes or anonymises all personal data within 30 days (GDPR Art. 17)
Subprocessor list maintained and disclosed (Stripe, Supabase, Vercel, Resend, etc.)
Data retention policy defined — how long different data types are retained

▸ Security Headers

Six HTTP security headers every SaaS product must set

These headers are configured in next.config.js under the headers() array. They cost nothing to add and eliminate multiple attack vectors.

Header
Value
Purpose
Required
Strict-Transport-Security
max-age=31536000; includeSubDomains; preload
Forces browsers to use HTTPS for all connections to the domain for 1 year
Yes
Content-Security-Policy
default-src 'self'; script-src 'self' 'nonce-{nonce}'; style-src 'self' 'unsafe-inline'
Controls what resources the browser is permitted to load, preventing XSS attacks
Yes
X-Frame-Options
DENY
Prevents the page from being embedded in an iframe on other origins, blocking clickjacking
Rec.
X-Content-Type-Options
nosniff
Prevents browsers from guessing the content type, blocking MIME-sniffing attacks
Rec.
Referrer-Policy
strict-origin-when-cross-origin
Limits what referrer data is sent with requests, protecting URL-embedded sensitive parameters
Rec.
Permissions-Policy
camera=(), microphone=(), geolocation=()
Restricts which browser features the page can access, reducing attack surface
Rec.

Add to next.config.js

headers: async () => [{
  source: '/(.*)',
  headers: [
    { key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubDomains' },
    { key: 'X-Frame-Options', value: 'DENY' },
    { key: 'X-Content-Type-Options', value: 'nosniff' },
  ]
}]

▸ Pre-Launch Summary

Security by layer — at a glance before you go live

Run through this summary the week before launch. Every category must pass before real users touch your product.

Auth

10 items
  • httpOnly JWT cookies
  • Email verification
  • Rate limiting on auth
  • PKCE for OAuth
  • Session invalidation on password change
  • + 5 more…

Database

10 items
  • RLS on all tenant tables
  • Cross-tenant leak test
  • No raw SQL concat
  • Service key server-side only
  • Encrypted sensitive fields
  • + 5 more…

API

10 items
  • Zod input validation
  • RBAC middleware
  • Org scoping on all queries
  • CORS restricted to origin
  • Error responses sans stack traces
  • + 5 more…

Infrastructure

10 items
  • HTTPS + HSTS
  • CSP header configured
  • No secrets in NEXT_PUBLIC_
  • Env vars per environment
  • Dependency scan in CI
  • + 5 more…

Billing

8 items
  • Webhook sig verification
  • State via webhooks only
  • Stripe key server-side
  • No card data on your servers
  • + 4 more…

Monitoring

8 items
  • Sentry error tracking
  • Uptime monitoring
  • Audit log table
  • Alert on auth failure burst
  • + 4 more…

Compliance

5 items
  • Privacy Policy published
  • Terms of Service accepted
  • User data export available
  • Account deletion process
  • + 1 more…

▸ Security Mistakes

Security mistakes that cause real breaches in production

These four mistakes appear repeatedly in SaaS security incidents. All are preventable and all are expensive once they've occurred with live user data.

Storing sensitive data in client-visible environment variables

Consequence

Any variable prefixed NEXT_PUBLIC_ is bundled into client-side JavaScript and visible to every user in the browser. Stripe secret keys, database URLs, and internal API keys exposed this way cause full platform compromise.

4Byte Standard

Only use NEXT_PUBLIC_ prefix for non-sensitive values. All secret keys, database URLs, and internal service tokens stay server-side only — never prefixed NEXT_PUBLIC_.

Testing RLS policies only for authorised access

Consequence

Teams verify that permitted users can read their data but never verify that non-members cannot. An RLS policy that's missing or misconfigured allows cross-tenant reads — which only shows up when tested from the wrong session.

4Byte Standard

Create a dedicated security test suite that explicitly attempts to read Organisation A's data from Organisation B's session. RLS must fail — not just succeed for authorised access.

Committing secrets to version control

Consequence

Even if a secret is committed and immediately deleted, it remains in git history permanently. Automated scanners continuously harvest secrets from GitHub repositories within minutes of a push.

4Byte Standard

Use .gitignore for all .env files from the first commit. Use a secrets manager (Doppler, Vercel env vars) for production. Rotate any secret that has ever touched version control.

No security review before launch

Consequence

Security issues found after launch with real users and real data cost 10–100× more to fix than the same issues found before launch. Data breaches post-launch carry regulatory and reputational consequences.

4Byte Standard

Run a pre-launch security checklist covering all 7 layers before any production deployment. This doesn't require a penetration test — systematic checklist review catches the most common and highest-impact vulnerabilities.

▸ FAQ

Frequently asked questions about SaaS security

What are the most important security controls for a SaaS product?+

The most critical SaaS security controls are: JWT tokens in httpOnly cookies, row-level security on every tenant table, Zod input validation on all API routes, rate limiting on auth endpoints, Stripe webhook signature verification, HTTPS with HSTS, and dependency scanning in CI/CD.

How do you prevent cross-tenant data leakage in a SaaS product?+

Cross-tenant data leakage is prevented through two layers: application-level scoping (all queries include WHERE organisation_id = current_org_id) and database-level RLS policies (PostgreSQL enforces tenant boundaries even if application code has a bug). Both must exist.

What security headers should a SaaS product set?+

Essential SaaS security headers: Strict-Transport-Security (enforces HTTPS), Content-Security-Policy (prevents XSS), X-Frame-Options: DENY (prevents clickjacking), X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin, and Permissions-Policy.

Is SaaS GDPR compliance required?+

GDPR compliance is required if your SaaS processes personal data of EU residents — regardless of where your company is based. Core requirements: privacy policy, DPA for B2B customers, user data export and deletion on request, and defined data retention policies.

How should SaaS environment variables and secrets be managed?+

Never commit secrets to version control. Use environment variables per environment (dev/staging/production). Store secrets in Vercel environment variables or a secrets manager like Doppler. Rotate any secret exposed in version control immediately. Audit production secret access quarterly.

How does 4Byte Agency approach SaaS security?+

4Byte Agency implements security-first across every build: RLS from migration zero, httpOnly JWT storage, Zod input validation on all routes, rate limiting on auth, HTTPS with security headers, Stripe webhook verification, dependency scanning in CI/CD, and a pre-launch security review across all 7 layers.

▸ Ship securely from day one

Want your SaaS product built with all 50+ controls in place?

We implement every control on this checklist — authentication hardening, RLS from migration zero, API validation, security headers, Stripe verification, and monitoring — before a single user signs up.

Available now
Security review included free
Response in ≤ 4 hours
45+ products shipped