All posts

How to Secure Your Next.js App: A Complete Guide with Ship Safe

Next.js is one of the most popular frameworks for building full-stack web applications. But with great power comes great attack surface: API routes, server components, middleware, environment variables, and client-side rendering all introduce security considerations.

This guide shows you how to use Ship Safe to audit your Next.js app for vulnerabilities and fix them before they ship.

Quick Start

cd your-nextjs-app
npx ship-safe audit .

Ship Safe automatically detects Next.js and adjusts its scanning accordingly.

1. Leaked Environment Variables

The most common Next.js security mistake: accidentally exposing secrets through NEXT_PUBLIC_ prefixed variables.

[SECRETS] API key exposed via NEXT_PUBLIC_ prefix
  .env.local:5 → NEXT_PUBLIC_STRIPE_SECRET_KEY should not use NEXT_PUBLIC_ prefix
  Severity: CRITICAL

The rule: Only use NEXT_PUBLIC_ for values that are safe to expose in the browser. Never for API keys, database URLs, or auth secrets.

2. Unprotected API Routes

Next.js API routes (both pages/api/ and app/api/) without authentication or rate limiting.

[AUTH] API route without authentication check
  app/api/users/route.ts:1 → Add auth middleware
  OWASP: A07:2025 Authentication Failures

Fix: Add auth checks and rate limiting to every state-changing route.

3. Server Actions Without Validation

Next.js Server Actions that accept user input without validation are vulnerable to injection and mass assignment attacks.

[INJECTION] Server Action processes unvalidated user input
  app/actions.ts:15 → Validate input with Zod schema
  OWASP: A03:2025 Injection

Fix: Use Zod schemas to validate all Server Action inputs. Whitelist allowed fields.

4. XSS via dangerouslySetInnerHTML

React's escape hatch for rendering raw HTML is a common XSS vector.

Fix: Always sanitize with DOMPurify before rendering user-provided HTML.

5. Missing Security Headers

Next.js doesn't set security headers by default. Ship Safe checks your next.config.js and middleware for Content-Security-Policy, X-Frame-Options, and others.

Fix: Configure headers in next.config.js using the headers() function.

6. Supabase RLS Issues

If you use Supabase with Next.js, Ship Safe's dedicated SupabaseRLSAgent checks for Row Level Security misconfigurations and service_role key exposure in client-side code.

CI/CD Integration

name: Security Audit
on: [push, pull_request]

jobs:
  ship-safe:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: asamassekou10/ship-safe@v6
        with:
          path: .
          threshold: 70
          github-pr: true

Next.js Security Checklist

After running npx ship-safe audit ., verify:

  • No secrets in NEXT_PUBLIC_ variables
  • All API routes have authentication
  • Rate limiting on auth endpoints
  • Server Actions validate input with Zod
  • dangerouslySetInnerHTML uses DOMPurify
  • Security headers configured in next.config.js
  • Supabase RLS enabled (if applicable)
  • Docker runs as non-root user
  • Dependencies are up to date
  • CI/CD pipeline includes security scanning

Ship fast. Ship safe.