Security context
Medium· 5.9GHSA-9g9p-9gw9-jx7f CVE-2025-59471CWE-400CWE-770Published Jan 27, 2026

Next.js self-hosted applications vulnerable to DoS via Image Optimizer remotePatterns configuration

Research this vulnerability

Research is free — Hunters explains how the bug works, the root-cause code pattern, how the fix addresses it, and how to test whether a target is affected, in chat. Investigate & write exploit is a paid run — the engine reads the advisory and fix commits, then builds and validates a working proof-of-concept exploit with reproduction steps.

Affected versions

10.0.0 → fixed in 15.5.1015.6.0-canary.0 → fixed in 16.1.5

Details

A DoS vulnerability exists in self-hosted Next.js applications that have `remotePatterns` configured for the Image Optimizer. The image optimization endpoint (`/_next/image`) loads external images entirely into memory without enforcing a maximum size limit, allowing an attacker to cause out-of-memory conditions by requesting optimization of arbitrarily large images. This vulnerability requires that `remotePatterns` is configured to allow image optimization from external domains and that the attacker can serve or control a large image on an allowed domain. Strongly consider upgrading to 15.5.10 and 16.1.5 to reduce risk and prevent availability issues in Next applications.

The fix

fetch(next/image): reduce maximumResponseBody from 300MB to

Steven· Jan 15, 2026, 07:34 PM+1111500ec83743
docs/01-app/03-api-reference/02-components/image.mdx+4 4
@@ -839,22 +839,22 @@ module.exports = {
#### `maximumResponseBody`
-The default image optimization loader will fetch source images up to 300 MB in size.
+The default image optimization loader will fetch source images up to 50 MB in size.
```js filename="next.config.js"
module.exports = {
images: {
- maximumResponseBody: 300_000_000,
+ maximumResponseBody: 50_000_000,
},
}
```
-If you know all your source images are small, you can protect memory constrained servers by reducing this to a smaller value such as 50 MB.
+If you know all your source images are small, you can protect memory constrained servers by reducing this to a smaller value such as 5 MB.
```js filename="next.config.js"
module.exports = {
images: {
- maximumResponseBody: 50_000_000,
+ maximumResponseBody: 5_000_000,
},
}
```
packages/next/src/shared/lib/image-config.ts+1 1
@@ -150,7 +150,7 @@ export const imageConfigDefault: ImageConfigComplete = {
minimumCacheTTL: 14400, // 4 hours
formats: ['image/webp'],
maximumRedirects: 3,
- maximumResponseBody: 300_000_000, // 300MB
+ maximumResponseBody: 50_000_000, // 50 MB
dangerouslyAllowLocalIP: false,
dangerouslyAllowSVG: false,
contentSecurityPolicy: `script-src 'none'; frame-src 'none'; sandbox;`,
test/integration/next-image-new/app-dir-localpatterns/test/index.test.ts+1 1
@@ -98,7 +98,7 @@ function runTests(mode: 'dev' | 'server') {
},
],
maximumRedirects: 3,
- maximumResponseBody: 300000000,
+ maximumResponseBody: 50000000,
minimumCacheTTL: 14400,
path: '/_next/image',
qualities: [75],
test/integration/next-image-new/app-dir-qualities/test/index.test.ts+1 1
@@ -110,7 +110,7 @@ function runTests(mode: 'dev' | 'server') {
},
],
maximumRedirects: 3,
- maximumResponseBody: 300000000,
+ maximumResponseBody: 50000000,
minimumCacheTTL: 14400,
path: '/_next/image',
qualities: [42, 69, 88],
test/integration/next-image-new/app-dir/test/index.test.ts+1 1
@@ -1796,7 +1796,7 @@ function runTests(mode: 'dev' | 'server') {
},
],
maximumRedirects: 3,
- maximumResponseBody: 300000000,
+ maximumResponseBody: 50000000,
minimumCacheTTL: 14400,
path: '/_next/image',
qualities: [75],
test/integration/next-image-new/unicode/test/index.test.ts+1 1
@@ -103,7 +103,7 @@ function runTests(mode: 'server' | 'dev') {
},
],
maximumRedirects: 3,
- maximumResponseBody: 300000000,
+ maximumResponseBody: 50000000,
minimumCacheTTL: 14400,
path: '/_next/image',
qualities: [75],
test/integration/next-image-new/unoptimized/test/index.test.ts+1 1
@@ -118,7 +118,7 @@ function runTests(url: string, mode: 'dev' | 'server') {
},
],
maximumRedirects: 3,
- maximumResponseBody: 300000000,
+ maximumResponseBody: 50000000,
minimumCacheTTL: 14400,
path: '/_next/image',
qualities: [75],
test/unit/image-optimizer/fetch-external-image.test.ts+1 1
@@ -19,7 +19,7 @@ describe('fetchExternalImage', () => {
const error = await fetchExternalImage(
'http://example.com/no-body.jpg',
false,
- 300_000_000
+ 50_000_000
).catch((e) => e)
expect(error).toBeInstanceOf(ImageError)

fetch(next/image): reduce maximumResponseBody from 300MB to

Steven· Jan 15, 2026, 07:34 PM+1111e5b834d208
docs/01-app/03-api-reference/02-components/image.mdx+4 4
@@ -776,22 +776,22 @@ module.exports = {
#### `maximumResponseBody`
-The default image optimization loader will fetch source images up to 300 MB in size.
+The default image optimization loader will fetch source images up to 50 MB in size.
```js filename="next.config.js"
module.exports = {
images: {
- maximumResponseBody: 300_000_000,
+ maximumResponseBody: 50_000_000,
},
}
```
-If you know all your source images are small, you can protect memory constrained servers by reducing this to a smaller value such as 50 MB.
+If you know all your source images are small, you can protect memory constrained servers by reducing this to a smaller value such as 5 MB.
```js filename="next.config.js"
module.exports = {
images: {
- maximumResponseBody: 50_000_000,
+ maximumResponseBody: 5_000_000,
},
}
```
packages/next/src/shared/lib/image-config.ts+1 1
@@ -140,7 +140,7 @@ export const imageConfigDefault: ImageConfigComplete = {
disableStaticImages: false,
minimumCacheTTL: 60,
formats: ['image/webp'],
- maximumResponseBody: 300_000_000, // 300MB
+ maximumResponseBody: 50_000_000, // 50 MB
dangerouslyAllowSVG: false,
contentSecurityPolicy: `script-src 'none'; frame-src 'none'; sandbox;`,
contentDispositionType: 'attachment',
test/integration/next-image-new/app-dir-localpatterns/test/index.test.ts+1 1
@@ -96,7 +96,7 @@ function runTests(mode: 'dev' | 'server') {
search: '',
},
],
- maximumResponseBody: 300000000,
+ maximumResponseBody: 50000000,
minimumCacheTTL: 60,
path: '/_next/image',
qualities: undefined,
test/integration/next-image-new/app-dir-qualities/test/index.test.ts+1 1
@@ -107,7 +107,7 @@ function runTests(mode: 'dev' | 'server') {
loaderFile: '',
remotePatterns: [],
localPatterns: undefined,
- maximumResponseBody: 300000000,
+ maximumResponseBody: 50000000,
minimumCacheTTL: 60,
path: '/_next/image',
qualities: [42, 69, 88],
test/integration/next-image-new/app-dir/test/index.test.ts+1 1
@@ -1634,7 +1634,7 @@ function runTests(mode: 'dev' | 'server') {
loaderFile: '',
remotePatterns: [],
localPatterns: undefined,
- maximumResponseBody: 300000000,
+ maximumResponseBody: 50000000,
minimumCacheTTL: 60,
path: '/_next/image',
qualities: undefined,
test/integration/next-image-new/unicode/test/index.test.ts+1 1
@@ -94,7 +94,7 @@ function runTests(mode: 'server' | 'dev') {
search: '',
},
],
- maximumResponseBody: 300000000,
+ maximumResponseBody: 50000000,
minimumCacheTTL: 60,
path: '/_next/image',
sizes: [
test/integration/next-image-new/unoptimized/test/index.test.ts+1 1
@@ -110,7 +110,7 @@ function runTests(url: string, mode: 'dev' | 'server') {
loaderFile: '',
remotePatterns: [],
localPatterns: undefined,
- maximumResponseBody: 300000000,
+ maximumResponseBody: 50000000,
minimumCacheTTL: 60,
path: '/_next/image',
qualities: undefined,
test/unit/image-optimizer/fetch-external-image.test.ts+1 1
@@ -18,7 +18,7 @@ describe('fetchExternalImage', () => {
const error = await fetchExternalImage(
'http://example.com/no-body.jpg',
- 300_000_000
+ 50_000_000
).catch((e) => e)
expect(error).toBeInstanceOf(ImageError)

References