Vercel has shipped a security release for Next.js: v16.4.5 (Active LTS) and v15.5.29 (Maintenance LTS). It fixes one high-severity and several medium-severity issues. Most of them involve Cache Components and use cache, where content generated for one tenant or user could be served to another.
If you run a Next.js app, especially a multi-tenant or self-hosted one, this guide explains what was fixed, how to check whether you’re affected, and how to upgrade safely.
Step 1: Check your version
npx next --version
# or
npm ls next
If you’re on the 16.x line below 16.4.5, or on 15.5.x below 15.5.29, you need to update.
Step 2: Upgrade
These are the commands from the official announcement:
npm install [email protected] # 16.x apps
npm install [email protected] # 15.5 apps
With pnpm or yarn:
pnpm add [email protected]
yarn add [email protected]
Then rebuild and redeploy. Lockfile-only changes don’t fix anything until the new build is running:
npm run build && npm run start
If your platform caches build output, clear the build cache on the next deploy so nothing stale survives.
What was fixed, in plain English
High: cross-tenant cache disclosure (unstable_cache + use cache)
Who is affected: apps with Cache Components enabled where the same public use cache function is called both directly and from inside unstable_cache, and that function reads a root parameter such as a tenant ID.
During a cold cache fill, a concurrent call could receive another request’s result. That result could then be stored and served to later callers, so one tenant could see another tenant’s data. Advisory: GHSA-mfr8-8qww-v76h.
Medium: issues around use cache
- Nested
use cachefunctions could store an outer entry before the inner function’s root-parameter dependencies were recorded. That could leak tenant-, site- or locale-specific content across boundaries (GHSA-vc7v-qv4w-wrv8). - Binary arguments passed to a
use cachefunction could produce the same cache key for different values. If you use binary arguments to tell users apart, one user could get another’s cached result (GHSA-rhh4-g77r-r9qj). - Shared shell cache poisoning in self-hosted apps running
next startwith Cache Components enabled and Partial Prefetching off, for a specific dynamic-route shape.
Medium: other fixes
- Cookie values exposed in Edge routes. Edge Route Handlers and Pages Router Edge API routes that set cookies with
NextResponse.cookies.set()could expose them in the internalx-middleware-set-cookieheader, which same-origin JavaScript can read, even forHttpOnlycookies (GHSA-f3mh-rxg3-f5g2). - Stale compressed response framing. Self-hosted apps that return an attacker-controlled fetched
Responseunchanged, behind certain HTTP/1.1 reverse proxies, could send responses to the wrong clients (GHSA-pc58-hwjq-p385). - SVG bypass in Image Optimization. A crafted image from an allowed source could be treated as AVIF and get past
images.dangerouslyAllowSVG: false(GHSA-7qx7-33qx-rqx2).
How to tell if you use Cache Components
Most of the serious issues only affect apps that use Cache Components and the use cache directive. A quick search of your codebase tells you whether that’s you:
grep -rn "use cache" app/ src/ lib/ 2>/dev/null
grep -rn "unstable_cache" app/ src/ lib/ 2>/dev/null
grep -rn "cacheComponents" next.config.* 2>/dev/null
If none of these return anything, the cache-related advisories very likely don’t apply to you. You should still upgrade for the cookie, image and response-framing fixes, but the urgency is lower. If they do return results, look for cached functions that read a root parameter, such as a tenant, site or locale segment. Those are the ones described in the high-severity advisory.
Also note whether you self-host with next start. Two of the medium issues (shared shell cache poisoning and stale compressed response framing) only apply to self-hosted setups with specific configurations.
Step 3: Review your code for risky patterns
Upgrading fixes the framework bugs, but a quick review of these patterns will make your app safer in general.
Keep tenant data out of shared caches by default
If a cached function returns tenant- or user-specific data, make the identifier an explicit argument, so it is always part of the cache key:
// lib/data.ts
export async function getDashboard(tenantId: string) {
'use cache';
// tenantId is an argument, so it is part of the cache key
const res = await fetch(`https://api.example.com/tenants/${tenantId}/dashboard`);
return res.json();
}
Avoid mixing old unstable_cache wrappers and use cache around the same function. Pick one approach and use it consistently.
Don’t use binary data as a cache identity
If you need to key a cache on a file or buffer, hash it into a string first:
import { createHash } from 'node:crypto';
export function keyFor(bytes: Uint8Array) {
return createHash('sha256').update(bytes).digest('hex');
}
Don’t pass upstream responses straight through
Instead of returning a fetched Response as-is, build a fresh one with only the headers you need:
// app/api/proxy/route.ts
export async function GET() {
const upstream = await fetch('https://api.example.com/data');
const body = await upstream.arrayBuffer();
return new Response(body, {
status: upstream.status,
headers: { 'content-type': upstream.headers.get('content-type') ?? 'application/json' },
});
}
Keep SVG optimization off unless you really need it
Leave images.dangerouslyAllowSVG at its default (false) and keep images.remotePatterns as narrow as possible:
// next.config.js
module.exports = {
images: {
remotePatterns: [{ protocol: 'https', hostname: 'cdn.example.com' }],
},
};
Test after upgrading
After the upgrade, run your usual test suite and then do a short manual check of the areas these fixes touch:
- Log in as two different users (or tenants) in separate browser profiles and confirm each sees only their own cached pages.
- Check that pages using
use cachestill revalidate when data changes. - If you use Edge routes that set cookies, open DevTools and confirm cookies still arrive through
Set-Cookieas expected. - Load a few optimized images to make sure your
imagesconfiguration still works.
Step 4: Automate future updates
Security releases are a good reminder to automate dependency updates. A minimal Dependabot config for an npm project looks like this:
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
Also turn on GitHub security alerts for the repository, so advisories like these reach you right away.
Takeaway
This release mostly matters for apps that use Cache Components and use cache, especially multi-tenant and self-hosted ones. The fix is simple: upgrade to [email protected] or [email protected], rebuild and redeploy. Then take ten minutes to check your caching and proxy code against the patterns above.
Sources: Next.js: November 2026 Security Release · Next.js v16.4.5 release
