Next.js: Server-Side Request Forgery in rewrites via attacker-controlled destination hostname
Affected releases · next
- 16.x16.0.0 – 16.2.10Fixed in 16.2.11
- 15.x15.0.0 – 15.5.20Fixed in 15.5.21
- 14.x14.0.0 – 14.2.35No fix on this line yet
- 13.x and older12.0.0 – 13.5.11No fix, no longer updated
On 16.x, the newest line:
npm install next@16.2.11Affected
16.0.0 – 16.2.10
31 releases
Fixed
16.2.11 – 16.4.2
14 releases, latest
Affected
15.0.0 – 15.5.20
74 releases
Fixed
15.5.21 – 15.5.28
8 releases
Affected
14.0.0 – 14.2.35
46 releases
Affected
13.0.0 – 13.5.11
56 releases
Affected
12.0.0 – 12.3.7
33 releases
Is your project affected?
Paste your package.json, or type the range you declare for next. It is read in your browser and sent nowhere.
What happens
Impact
A rewrites() or redirects() rule that builds its external destination hostname from request-controlled input can be pointed at an arbitrary hostname, regardless of the rule's hostname suffix. For a rewrite, Next.js proxies the request to that arbitrary host and serves the response from the application's origin, leading to Server-Side Request forgery. A redirects() rule configured this way is vulnerable to an Open Redirect.
This affects any destination that puts a dynamic segment in the hostname, whether from the path:
// next.config.js
module.exports = {
async rewrites() {
return [
{
source: '/:tenant',
destination: 'https://:tenant.api.example.com',
},
]
},
}or from a has capture:
// next.config.js
module.exports = {
async rewrites() {
return [
{
source: '/',
has: [{ type: 'query', key: 'region', value: '(?<region>.+)' }],
destination: 'https://:region.api.example.com',
},
]
},
}Workarounds
If you cannot upgrade immediately, do not build the hostname of an external rewrites() or redirects() destination from user-controlled input. If a dynamic subdomain is required, constrain the value to hostname-safe characters: value: '(?<region>[a-z0-9-]+)'.