VYPR
Critical severityNVD Advisory· Published Mar 21, 2025· Updated Apr 8, 2025

Authorization Bypass in Next.js Middleware

CVE-2025-29927

Description

Next.js is a React framework for building full-stack web applications. Starting in version 1.11.4 and prior to versions 12.3.5, 13.5.9, 14.2.25, and 15.2.3, it is possible to bypass authorization checks within a Next.js application, if the authorization check occurs in middleware. If patching to a safe version is infeasible, it is recommend that you prevent external user requests which contain the x-middleware-subrequest header from reaching your Next.js application. This vulnerability is fixed in 12.3.5, 13.5.9, 14.2.25, and 15.2.3.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
nextnpm
>= 13.0.0, < 13.5.913.5.9
nextnpm
>= 14.0.0, < 14.2.2514.2.25
nextnpm
>= 15.0.0, < 15.2.315.2.3
nextnpm
>= 12.0.0, < 12.3.512.3.5

Affected products

1

Patches

2
5fd3ae8f8542

[backport] Update middleware request header (#77202)

https://github.com/vercel/next.jsJJ KasperMar 17, 2025via ghsa
4 files changed · +34 0
  • packages/next/src/server/lib/router-server.ts+6 0 modified
    @@ -149,6 +149,12 @@ export async function initialize(opts: {
       renderServer.instance =
         require('./render-server') as typeof import('./render-server')
     
    +  const randomBytes = new Uint8Array(8)
    +  crypto.getRandomValues(randomBytes)
    +  const middlewareSubrequestId = Buffer.from(randomBytes).toString('hex')
    +  ;(globalThis as any)[Symbol.for('@next/middleware-subrequest-id')] =
    +    middlewareSubrequestId
    +
       const requestHandlerImpl: WorkerRequestHandler = async (req, res) => {
         // internal headers should not be honored by the request handler
         if (!process.env.NEXT_PRIVATE_TEST_HEADERS) {
    
  • packages/next/src/server/lib/server-ipc/utils.ts+11 0 modified
    @@ -57,5 +57,16 @@ export const filterInternalHeaders = (
         if (INTERNAL_HEADERS.includes(header)) {
           delete headers[header]
         }
    +
    +    // If this request didn't origin from this session we filter
    +    // out the "x-middleware-subrequest" header so we don't skip
    +    // middleware incorrectly
    +    if (
    +      header === 'x-middleware-subrequest' &&
    +      headers['x-middleware-subrequest-id'] !==
    +        (globalThis as any)[Symbol.for('@next/middleware-subrequest-id')]
    +    ) {
    +      delete headers['x-middleware-subrequest']
    +    }
       }
     }
    
  • packages/next/src/server/web/sandbox/context.ts+4 0 modified
    @@ -365,6 +365,10 @@ Learn More: https://nextjs.org/docs/messages/edge-dynamic-code-evaluation`),
                 store.headers.get('x-middleware-subrequest') ?? ''
               )
             }
    +        init.headers.set(
    +          'x-middleware-subrequest-id',
    +          (globalThis as any)[Symbol.for('@next/middleware-subrequest-id')]
    +        )
     
             const prevs =
               init.headers.get(`x-middleware-subrequest`)?.split(':') || []
    
  • test/e2e/middleware-general/test/index.test.ts+13 0 modified
    @@ -102,6 +102,19 @@ describe('Middleware Runtime', () => {
       }
     
       function runTests({ i18n }: { i18n?: boolean }) {
    +    it('should filter request header properly', async () => {
    +      const res = await next.fetch('/redirect-to-somewhere', {
    +        headers: {
    +          'x-middleware-subrequest':
    +            'middleware:middleware:middleware:middleware:middleware',
    +        },
    +        redirect: 'manual',
    +      })
    +
    +      expect(res.status).toBe(307)
    +      expect(res.headers.get('location')).toContain('/somewhere')
    +    })
    +
         it('should handle 404 on fallback: false route correctly', async () => {
           const res = await next.fetch('/ssg-fallback-false/first')
           expect(res.status).toBe(200)
    
52a078da3884

Update middleware request header (#77201)

https://github.com/vercel/next.jsJJ KasperMar 17, 2025via ghsa
4 files changed · +35 4
  • packages/next/src/server/lib/router-server.ts+7 4 modified
    @@ -166,10 +166,13 @@ export async function initialize(opts: {
       renderServer.instance =
         require('./render-server') as typeof import('./render-server')
     
    -  const allowedOrigins = [
    -    'localhost',
    -    ...(config.experimental.allowedDevOrigins || []),
    -  ]
    +  const randomBytes = new Uint8Array(8)
    +  crypto.getRandomValues(randomBytes)
    +  const middlewareSubrequestId = Buffer.from(randomBytes).toString('hex')
    +  ;(globalThis as any)[Symbol.for('@next/middleware-subrequest-id')] =
    +    middlewareSubrequestId
    +
    +  const allowedOrigins = ['localhost', ...(config.allowedDevOrigins || [])]
       if (opts.hostname) {
         allowedOrigins.push(opts.hostname)
       }
    
  • packages/next/src/server/lib/server-ipc/utils.ts+11 0 modified
    @@ -57,5 +57,16 @@ export const filterInternalHeaders = (
         if (INTERNAL_HEADERS.includes(header)) {
           delete headers[header]
         }
    +
    +    // If this request didn't origin from this session we filter
    +    // out the "x-middleware-subrequest" header so we don't skip
    +    // middleware incorrectly
    +    if (
    +      header === 'x-middleware-subrequest' &&
    +      headers['x-middleware-subrequest-id'] !==
    +        (globalThis as any)[Symbol.for('@next/middleware-subrequest-id')]
    +    ) {
    +      delete headers['x-middleware-subrequest']
    +    }
       }
     }
    
  • packages/next/src/server/web/sandbox/context.ts+4 0 modified
    @@ -373,6 +373,10 @@ Learn More: https://nextjs.org/docs/messages/edge-dynamic-code-evaluation`),
                 store.headers.get('x-middleware-subrequest') ?? ''
               )
             }
    +        init.headers.set(
    +          'x-middleware-subrequest-id',
    +          (globalThis as any)[Symbol.for('@next/middleware-subrequest-id')]
    +        )
     
             const prevs =
               init.headers.get(`x-middleware-subrequest`)?.split(':') || []
    
  • test/e2e/middleware-general/test/index.test.ts+13 0 modified
    @@ -144,6 +144,19 @@ describe('Middleware Runtime', () => {
           }
         }
     
    +    it('should filter request header properly', async () => {
    +      const res = await next.fetch('/redirect-to-somewhere', {
    +        headers: {
    +          'x-middleware-subrequest':
    +            'middleware:middleware:middleware:middleware:middleware',
    +        },
    +        redirect: 'manual',
    +      })
    +
    +      expect(res.status).toBe(307)
    +      expect(res.headers.get('location')).toContain('/somewhere')
    +    })
    +
         it('should handle 404 on fallback: false route correctly', async () => {
           const res = await next.fetch('/ssg-fallback-false/first')
           expect(res.status).toBe(200)
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

11

News mentions

3