← All cybersecurity posts

Next.js Security Best Practices

Next.js blurs the line between frontend and backend. Server components, server actions and route handlers run on the server, right next to client code. That is productive, and it makes it easy to forget which code is a public API.

Server actions and route handlers are public endpoints

Every server action and route handler can be called directly by anyone, not just from your UI. Treat each one like an API endpoint:

"use server";
export async function deleteProject(id: string) {
  const session = await getSession();
  if (!session) throw new Error("Unauthorized");
  const project = await db.project.findFirst({ where: { id, orgId: session.orgId } });
  if (!project) throw new Error("Not found");
  await db.project.delete({ where: { id: project.id } });
}
  • Authenticate in every action and handler.
  • Authorise the specific object, scoped to the user or organisation.
  • Validate input with a schema; arguments come from the client.

Do not rely on middleware alone for authorisation

Middleware is useful for redirects and coarse checks, but authorisation decisions should also be enforced where data is accessed. Next.js has had a past vulnerability where middleware could be bypassed with a crafted header, which was patched. Keep Next.js updated, and check access in the data layer too, so a middleware gap does not expose data.

Keep secrets out of the client bundle

  • Environment variables prefixed with NEXT_PUBLIC_ are embedded in client JavaScript and visible to everyone. Never put secrets there.
  • Import server-only modules with the server-only package so accidental client imports fail at build time.
  • Review what your build outputs to the browser.

Avoid leaking data from server to client components

Passing a full database object as a prop to a client component serialises every field into the page, including fields you did not display, such as emails, internal flags or hashes.

  • Pass only the fields the component needs.
  • Use data transfer objects or select specific columns.
  • Consider React's taint APIs, where available, to prevent sensitive values reaching the client.

Rendering user content safely

React escapes output by default. Risks return with dangerouslySetInnerHTML, Markdown rendering and user-controlled href values. Sanitise HTML and validate URL schemes.

Security headers

Configure headers in next.config.js or middleware: Content Security Policy, preferably nonce-based, HSTS, X-Content-Type-Options, Referrer-Policy and framing protection. See our security headers guide.

Image and fetch features

  • Restrict images.remotePatterns to domains you trust, to avoid your server fetching arbitrary URLs.
  • Validate any user-supplied URLs fetched on the server to prevent SSRF.

Caching and data exposure

Be careful that personalised responses are not cached and served to other users. Mark user-specific routes as dynamic and send Cache-Control: private, no-store where appropriate.

Keep dependencies current

Next.js and React release security fixes regularly. Enable automated dependency updates and apply security releases quickly.

Next.js security checklist

AreaCheck
Server actions and handlersAuthenticated, authorised, validated
MiddlewareNot the only authorisation layer
Environment variablesNo secrets with NEXT_PUBLIC_
Server to client propsMinimal fields only
User contentSanitised HTML, safe URLs
HeadersCSP, HSTS and others set
Remote imagesRestricted patterns
CachingNo shared caching of personal data
UpdatesNext.js and React patched

Testing your Next.js app

SecurityInfinity discovers server actions and API routes, tests them with multiple identities, checks client bundles for exposed secrets and verifies headers and caching. Start free.

Frequently asked questions

Are server actions secure by default?

They include some protections, such as origin checks, but authentication and authorisation are your responsibility in every action.

Is it safe to put API keys in Next.js environment variables?

Yes, if they are not prefixed with NEXT_PUBLIC_ and are only used in server code.

Do I still need CSRF protection in Next.js?

Server actions use POST and check origins, which mitigates CSRF. Custom route handlers using cookies should still verify origin or use tokens.

Find what attackers can see, before they do.

AI pentesting agents test your web app, API and cloud, and every finding comes with evidence and a fix. First report in about 10 minutes.

Stay ahead of attackers.

New vulnerabilities, breach write-ups and practical fixes. A few emails a month.