AI QA Monkey
AI Security Intelligence
React / Next.js

React & Next.js Security Checklist 2026: Production Hardening Guide

Modern JS stacks ship fast, but speed without guardrails creates security debt. This checklist helps teams harden React and Next.js production apps with controls that reduce exploitability quickly.

Critical checks first

  • Ban unsafe rendering patterns unless sanitized and reviewed.
  • Verify no secrets are exposed via client-side env vars.
  • Audit API routes for auth, rate limits, and input validation.
  • Disable or tightly control production source maps.
  • Apply strict CSP and cookie/session hardening.

Next.js-specific hardening

  • Review server components and API handlers for data leakage.
  • Validate middleware auth logic across all protected routes.
  • Ensure SSR responses do not expose internal tokens/debug info.

Operational checklist

  • Dependency vulnerability scanning in CI.
  • Release gate for security regressions.
  • Weekly external scan + monthly deeper review.

Copy-paste checklist for CI/CD gates

# Pre-deploy security gate
1. No dangerouslySetInnerHTML without DOMPurify
2. No NEXT_PUBLIC_ secrets in .env
3. All API routes behind auth middleware
4. productionBrowserSourceMaps: false in next.config.js
5. CSP header set in next.config.js headers()
6. HttpOnly + Secure + SameSite=Strict on all session cookies
7. npm audit --audit-level=high passes

Dependency and supply chain security

  • Run npm audit or yarn audit in CI on every PR. Block merge on high/critical findings.
  • Pin dependency versions and use a lock file. Review package-lock.json diffs on every dependency update.
  • Avoid packages with very few downloads or single maintainers for security-critical code paths.
  • Use XSS prevention techniques consistently across all rendering contexts.

CORS and API exposure

React XSS prevention patterns

React's JSX automatically escapes values in expressions, but several patterns bypass this protection and create XSS vulnerabilities in production applications.

  • dangerouslySetInnerHTML: The name is a deliberate warning. Any usage must sanitize the input with DOMPurify before injection. Audit every instance in the codebase during code review.
  • URL injection in href and src: Never set href={userInput} directly. Validate URLs start with https:// or use a whitelist. javascript: URLs will execute in href contexts.
  • Template literals in style objects: Inline style values derived from user input can inject CSS expressions in older browsers. Always sanitize or validate before injecting into style props.
  • Third-party component innerHTML: Rich text editors, charting libraries, and markdown renderers often accept raw HTML. Review their sanitization documentation before passing user content.

Next.js security headers in next.config.js

Next.js allows you to add security headers globally via the headers()next.config.js. These headers should be applied to all routes.

// next.config.js
const securityHeaders = [
  { key: 'X-DNS-Prefetch-Control', value: 'on' },
  { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' },
  { key: 'X-Frame-Options', value: 'SAMEORIGIN' },
  { key: 'X-Content-Type-Options', value: 'nosniff' },
  { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
  { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
];

module.exports = {
  async headers() {
    return [{ source: '/(.*)', headers: securityHeaders }];
  },
  productionBrowserSourceMaps: false,
};

Authentication and session management

Client-side authentication in React/Next.js creates unique challenges. Tokens stored incorrectly are exposed to XSS; sessions managed poorly create CSRF risk.

  • Store JWTs in HttpOnly cookies, not localStorage: LocalStorage is accessible by any JavaScript on the page. An XSS vulnerability means full token theft. Use Set-Cookie: HttpOnly; Secure; SameSite=Strict.
  • Use NextAuth.js or a dedicated auth library: Rolling your own auth in Next.js API routes is a common source of session fixation, token leakage, and CSRF vulnerabilities.
  • Validate tokens server-side on every API request: Never trust client-side state for authorization decisions. Verify JWTs or session tokens on every API route handler.
  • Implement token rotation: Short-lived access tokens (15 minutes) with longer-lived refresh tokens reduce the impact window of a stolen token.

Server Component security in Next.js App Router

Next.js App Router introduced Server Components that execute on the server. This creates new security considerations that do not exist in traditional React SPAs.

  • Never expose sensitive data in Server Component props: Data fetched in Server Components and passed as props is serialized into the HTML payload. Filter sensitive fields before returning data.
  • Validate authentication in Server Components: Do not assume middleware auth checks are sufficient. Validate session in every Server Component that renders protected data.
  • Avoid passing user-controlled data to dangerouslySetInnerHTML from server: Server-rendered HTML is trusted by the browser. XSS in SSR context can bypass client-side defenses.
  • Review getServerSideProps data leaks: All data returned from getServerSideProps is embedded in the page HTML as JSON. Audit what is returned — it is publicly visible in the page source.

Next.js API routes: common security mistakes

Next.js API routes (/pages/api/ or /app/api/) are full server-side endpoints, but developers frequently treat them with less rigor than backend API services — leading to predictable vulnerabilities.

  • Missing authentication checks: Every API route that returns or modifies user data must verify authentication. Do not rely on the frontend to restrict access — API routes are directly accessible via any HTTP client regardless of what the UI shows.
  • No HTTP method validation: Validate the request method explicitly. A route that should only accept POST should return 405 Method Not Allowed for GET, PUT, and DELETE — not process them silently.
  • Exposing environment variables: Variables prefixed with NEXT_PUBLIC_ are bundled into the client-side JavaScript. Never prefix sensitive values (API keys, secrets, database URLs) with NEXT_PUBLIC_. Only public, non-sensitive values should use this prefix.
  • Unvalidated request bodies: Parse and validate all request body fields. Use zod, yup, or similar schema validation on every API route handler — never pass raw req.body fields to database queries or external services.
  • Missing rate limiting: API routes have no built-in rate limiting. Implement it with upstash/ratelimit, express-rate-limit (in custom server setups), or Vercel's edge middleware. Auth and OTP routes are the highest priority.
// Example: validated and authenticated Next.js API route
import { z } from 'zod';
import { getServerSession } from 'next-auth';

const schema = z.object({ email: z.string().email(), message: z.string().max(1000) });

export default async function handler(req, res) {
  if (req.method !== 'POST') return res.status(405).end();

  const session = await getServerSession(req, res, authOptions);
  if (!session) return res.status(401).json({ error: 'Unauthorized' });

  const result = schema.safeParse(req.body);
  if (!result.success) return res.status(400).json({ error: 'Invalid input' });

  // Process result.data — not req.body directly
}

Dependency security in React projects

React applications typically have hundreds of npm dependencies. Vulnerabilities in dependencies are a major source of supply chain risk — especially in packages that handle parsing, authentication, or HTTP.

  • Run npm audit in CI: Add npm audit --audit-level=high to your CI pipeline. Block merges when high or critical vulnerabilities are detected in direct dependencies.
  • Use npm audit fix regularly: Many vulnerabilities are fixed by minor version updates. Run npm audit fix weekly and review the diff for any unexpected major version changes.
  • Lock transitive dependencies with package-lock.json: Always commit your lockfile. This ensures consistent, reproducible builds and prevents transitive dependency substitution attacks.
  • Enable Dependabot or Renovate: Automated dependency update PRs with security alerts ensure vulnerabilities are surfaced and patched quickly without manual monitoring overhead.
  • Audit installed packages for malicious behavior: Use npm-audit-fix and periodically review the node_modules/.bin scripts installed by dependencies. Malicious packages have historically installed web shells, crypto miners, and data exfiltration scripts.

Content Security Policy for React apps

CSP is particularly important for React SPAs because the entire application logic runs in the browser — a successful XSS attack has full application context. Implementing a strict CSP is the most effective defense-in-depth layer against XSS in React applications.

// next.config.js — CSP via security headers
const ContentSecurityPolicy = `
  default-src 'self';
  script-src 'self' 'nonce-${nonce}';
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  font-src 'self';
  connect-src 'self' https://api.yourdomain.com;
  object-src 'none';
  base-uri 'self';
  form-action 'self';
  frame-ancestors 'none';
`;

// Generate a unique nonce per request and add to all script tags
// Use Next.js middleware to inject nonce into CSP header and page context

The nonce-based approach is the only CSP strategy that works reliably with React — hash-based CSP requires regenerating hashes every time bundled scripts change. See the security headers guide for full CSP implementation details.

Scan your React or Next.js app now

Detect env leaks, API exposure, CORS issues, source map risks, and hardening gaps in under 60 seconds.

Run React/Node Security Scan

Check Your Website Right Now

Run a free automated security scan — 75 checks in 60 seconds. No signup required.

Run Free Security Scan →