- Published on
Next.js July 2026 Security Release: Upgrade, Verify, and Reduce Server-Side Risk
- Authors

- Name
- Maria
On July 20, 2026, the Next.js team announced a coordinated security release for the supported 15.x and 16.x lines. The patched versions are:
- Next.js 16.2.11 for the Active LTS line;
- Next.js 15.5.21 for the Maintenance LTS line.
The release addresses four high-severity and five medium-severity vulnerabilities. The practical response is not to reproduce each exploit. It is to identify every deployed Next.js application, upgrade the supported line, review the affected architectural features, and verify that production is actually serving the patched build.
This guide explains that process. It focuses on App Router applications, Server Actions, custom servers, proxies, and dynamic rewrite rules because those boundaries appear repeatedly in the published advisories.
TL;DR If an application runs Next.js 15.x, upgrade to at least
15.5.21. If it runs Next.js 16.x, upgrade to at least16.2.11. Do not treat a lockfile change as proof of remediation: rebuild, deploy, and verify the runtime version. Review Server Actions as public server endpoints, validate authorization inside each action, and never build an external rewrite hostname from unchecked request input.
What Changed in the July 2026 Release
The official release covers several independent vulnerabilities rather than one shared root cause. Among the published advisories are:
- denial of service through crafted requests to an App Router application with at least one Server Action;
- server-side request forgery or open redirect when an external rewrite or redirect constructs its hostname from request-controlled input;
- server-side request forgery involving Server Actions on certain custom-server or proxy deployments where clients can influence host-related headers;
- unauthenticated disclosure of internal Server Function endpoint identifiers.
These issues do not affect every Next.js application in the same way. A static export with no server runtime has a different exposure from an App Router application that uses Server Actions. A managed deployment that pins the incoming host has a different boundary from a custom Node server behind a permissive proxy.
The version upgrade is still the first action because some advisories have no complete workaround other than upgrading. Architecture review comes next because a patched framework cannot compensate for an application that trusts request input as authorization or intentionally proxies to arbitrary hosts.
Supported Versions and the Upgrade Decision
The security release names two supported targets:
| Current line | Supported target | Support status |
|---|---|---|
| Next.js 16.2.x | 16.2.11 or later compatible patch | Active LTS |
| Next.js 15.5.x | 15.5.21 or later compatible patch | Maintenance LTS |
| Older 15.x | Move to 15.5.21 or a supported 16.x line | Do not remain on an unpatched minor |
| 14.x or earlier | Plan a supported-line migration immediately | Not a target of this coordinated patch |
A security incident is the wrong time to combine an untested major-version migration with emergency remediation. If an application is already on 15.5, moving to 15.5.21 is the smallest supported change. A planned migration to 16.x can continue separately after the patch is deployed.
For a 16.2 application, update within the same line:
{
"dependencies": {
"next": "16.2.11"
}
}
For a 15.5 application:
{
"dependencies": {
"next": "15.5.21"
}
}
Use an exact version for an emergency security rollout if your team wants the reviewed artifact to remain identical across clean installations. If your repository intentionally uses a compatible range, confirm that the lockfile resolves to the patched version and that deployment does not reuse an older dependency cache.
Upgrade the Dependency and Lockfile Together
Use the package manager declared by the repository. Do not manually edit only package.json, because production normally installs the graph recorded in the lockfile.
npm
npm install --save-exact next@15.5.21
npm ls next
For the 16.2 line:
npm install --save-exact next@16.2.11
npm ls next
pnpm
pnpm add --save-exact next@15.5.21
pnpm why next
Yarn
yarn add --exact next@15.5.21
yarn why next
After installation, inspect both the manifest and lockfile:
git diff -- package.json yarn.lock
The equivalent command can include package-lock.json or pnpm-lock.yaml. The important checks are:
- the direct
nextdependency resolves to the intended patch; - the lockfile does not retain an older Next.js package through an unexpected workspace;
- React and React DOM remain on versions compatible with the chosen Next.js line;
- post-install scripts or package-manager overrides do not replace the selected version.
In a monorepo, search every workspace. A patched frontend does not remediate an internal admin application that still deploys an affected version.
find . -name package.json -not -path '*/node_modules/*' -print
Prefer a workspace-aware dependency command when available rather than relying only on this file listing.
Determine Whether App Router and Server Actions Are Exposed
The App Router lives under the app directory. Server Actions are server functions marked with the use server directive or exported from a server-only action module.
'use server'
import { auth } from '@/lib/auth'
export async function updateProfile(input: FormData) {
const session = await auth()
if (!session?.user) {
throw new Error('Unauthorized')
}
const displayName = String(input.get('displayName') ?? '')
// Validate input and enforce resource-level authorization here.
}
The authorization check belongs inside the Server Action. Hiding a form on a protected page is not sufficient. Server Function identifiers can appear in client artifacts, and any server endpoint must treat the request as untrusted.
Inventory actions with a source search:
rg -n --glob '*.{js,jsx,ts,tsx}' \
"^[\"']use server[\"']|use server" app src
For every result, answer:
- Does the function authenticate the caller?
- Does it authorize access to the specific tenant, account, or resource?
- Is input validated before it reaches a database, filesystem, template, or outbound request?
- Can repeated execution create duplicate side effects?
- Are expensive operations bounded by size, duration, and concurrency controls?
The July denial-of-service advisory specifically identifies App Router applications with at least one Server Action. Pages Router applications and applications without Server Actions are not affected by that advisory, but they may still match a different advisory in the coordinated release.
Review Rewrites and Redirects for Request-Controlled Hosts
Next.js supports rewrites and redirects in next.config.js. They are often used for migrations, multi-region routing, or proxying a stable application path to another service.
The dangerous pattern is placing a request-controlled capture directly into the hostname of an external destination:
module.exports = {
async rewrites() {
return [
{
source: '/:tenant',
destination: 'https://:tenant.api.example.com',
},
]
},
}
Path matching does not automatically make the captured value a safe DNS label. A broad capture can alter the destination in ways the rule author did not intend. For a rewrite, the server may make the outbound request and return the response under the application's origin. For a redirect, the browser can be sent to an attacker-selected destination.
The preferred design is an explicit allowlist:
const tenantOrigins = {
alpha: 'https://alpha.api.example.com',
beta: 'https://beta.api.example.com',
}
module.exports = {
async rewrites() {
return Object.entries(tenantOrigins).map(([tenant, origin]) => ({
source: `/${tenant}/:path*`,
destination: `${origin}/:path*`,
}))
},
}
If the set is too large for static configuration, resolve the tenant on the server, validate it against authoritative data, and construct the outbound request after authorization. Do not accept a full URL or hostname from a query parameter and pass it to fetch.
When a regex capture is unavoidable, constrain it to a valid expected alphabet and still verify it against an allowlist:
{
source: '/',
has: [
{
type: 'query',
key: 'region',
value: '(?<region>[a-z0-9-]+)',
},
],
destination: 'https://:region.api.example.com',
}
Character restrictions reduce parser ambiguity but do not prove that the resulting subdomain is authorized. Treat them as defense in depth, not the primary trust decision.
Pin Host Headers at the Edge
One published advisory concerns Server Actions on custom-server deployments where attacker-controlled host-related headers can influence a server-side request. The official advisory notes that managed hosting pins the host upstream, and that next start and standalone output do so on supported versions. Custom servers and unusual proxy chains need explicit review.
At the first trusted proxy:
- replace, rather than append to,
HostandX-Forwarded-Host; - pass a known canonical origin to the application;
- reject unexpected public hostnames;
- ensure direct access to the application server is blocked.
An Nginx boundary can look like this:
server {
listen 443 ssl;
server_name app.example.com;
location / {
proxy_set_header Host app.example.com;
proxy_set_header X-Forwarded-Host app.example.com;
proxy_set_header X-Forwarded-Proto https;
proxy_pass http://nextjs_upstream;
}
}
The exact configuration depends on the platform. The invariant is that an internet client cannot choose the origin that trusted server-side logic uses.
If an emergency upgrade is temporarily blocked, the advisory describes pinning these headers and, for supported 14.2-or-later deployments, setting __NEXT_PRIVATE_ORIGIN to the real origin. That is a temporary mitigation, not a substitute for installing the patched release.
Test the Patched Application
Security remediation needs evidence at four layers.
1. Dependency verification
yarn why next
Record the resolved version in the change ticket or deployment report.
2. Build verification
yarn build
Treat new compilation errors as real migration work. Do not bypass type checking or linting merely to complete a security deployment.
3. Application smoke tests
Run tests for:
- public and authenticated routes;
- Server Actions with authorized, unauthorized, and malformed input;
- redirects and rewrites;
- middleware and proxy authorization;
- image optimization and route handlers;
- cache invalidation and revalidation;
- custom-server startup, if used.
A small authorization test for a Server Action should prove that access is checked inside the action:
it('rejects an unauthenticated profile update', async () => {
mockAuth.mockResolvedValue(null)
await expect(updateProfile(new FormData())).rejects.toThrow('Unauthorized')
expect(profileRepository.update).not.toHaveBeenCalled()
})
4. Runtime verification
Deploy a newly built artifact and verify:
- the deployment commit matches the reviewed commit;
- the build log installed the patched version;
- old containers or serverless functions were replaced;
- health checks and key routes return expected responses;
- error rate, CPU, outbound connections, and latency remain normal.
If the organization creates a software bill of materials, regenerate it and confirm that the old Next.js version is absent.
Safe Validation Without Reproducing Exploits
There is rarely a good reason to send production exploit payloads. Validate the controls instead:
- unit-test hostname allowlists and rejected inputs;
- integration-test that the proxy replaces hostile host headers;
- test that unauthenticated Server Action calls fail before business work;
- place strict timeouts and egress controls around outbound requests;
- monitor for unexpected connections to link-local, loopback, or private address ranges;
- load-test normal Server Action traffic with bounded payloads.
For SSRF defense, application validation is only one layer. Network policy should prevent the workload from reaching cloud metadata endpoints and unrelated private services. DNS resolution and redirects can change after an initial validation, so outbound access should be restricted at the network layer when practical.
For denial-of-service resilience, use platform-level request size limits, timeouts, concurrency protection, and rate limits. These controls reduce blast radius but do not replace the framework patch.
Rollout and Rollback Plan
A patch release should have a short rollout plan:
- update the supported Next.js line and lockfile;
- run unit, integration, and production builds;
- deploy to a preview or staging environment;
- verify routes, actions, rewrites, and proxy behavior;
- deploy a canary slice if the platform supports it;
- monitor errors, CPU, latency, and outbound connections;
- complete the rollout;
- retain the previous artifact only for rollback.
Rollback creates a security trade-off because it may restore a vulnerable version. If the patched build fails, prefer fixing the compatibility issue quickly or temporarily disabling the affected feature. Document who can authorize a rollback and which compensating controls must be enabled.
When to Upgrade Now and When to Plan a Larger Migration
Upgrade now when:
- production resolves Next.js below
15.5.21on the 15.5 line; - production resolves Next.js below
16.2.11on the 16.2 line; - the application uses App Router, Server Actions, a custom server, or external rewrites;
- the internet can reach the server runtime;
- the team cannot confidently prove that none of the published conditions apply.
Keep the emergency change small when:
- the application is on 15.5 and a move to 16.x requires code migration;
- the major-version migration has not completed staging tests;
- unrelated dependency updates would make rollback and diagnosis harder.
Plan a separate modernization task when:
- the application is on an unsupported Next.js release;
- Pages Router to App Router migration is desired;
- custom proxy or server code has unclear ownership;
- authorization is enforced only by page visibility or middleware;
- dynamic destinations and broad egress are part of the current design.
Security patching and architectural improvement are complementary. The patch closes known framework vulnerabilities; the follow-up work removes fragile trust assumptions.
Operational Checklist
- Inventory every deployed Next.js application and workspace.
- Upgrade 15.5 to
15.5.21or 16.2 to16.2.11. - Commit the manifest and lockfile together.
- Review all
use serverfunctions for in-function authentication and authorization. - Review external rewrites and redirects for request-controlled hostnames.
- Verify the trusted proxy pins
HostandX-Forwarded-Host. - Run the production build and application tests.
- Deploy a newly built artifact and verify its resolved Next.js version.
- Monitor CPU, errors, latency, and unusual outbound traffic.
- Track unsupported applications as a separate migration risk.
For a broader discussion of edge authentication, routing, and resilience boundaries, see Spring Cloud Gateway with Spring Boot 4: Routing, Security, Resilience, and BFF Composition.
Official References
- Next.js July 2026 Security Release
- Denial of Service in App Router using Server Actions
- SSRF in rewrites via an attacker-controlled destination hostname
- SSRF in Server Actions on custom servers
- Disclosure of internal Server Function endpoints
Conclusion
The July 2026 Next.js release is an upgrade event, not just a security-news item. Move supported applications to 15.5.21 or 16.2.11, rebuild the deployment artifact, and verify the resolved runtime version.
Then inspect the application boundaries highlighted by the advisories. Server Actions must authenticate and authorize inside the function. Rewrites must not turn request input into an arbitrary destination. Proxies must define the canonical host rather than trusting the client. Outbound network access should be constrained.
That combination—patched dependencies, explicit trust boundaries, and verifiable deployment evidence—is more durable than treating a security release as a one-line version change.