Zero-Day & Exploits
Next.js: bypass de autorização além do middleware
Um roteiro técnico para comparar HTML, RSC e APIs, revisar as CVEs de middleware e prefetch e testar autorização por usuário, tenant e objeto.
Uma página que redireciona para o login não prova que os dados por trás dela estão protegidos. Em aplicações Next.js, HTML, navegação do cliente, respostas RSC e handlers podem alcançar o mesmo recurso por caminhos diferentes. O pentest precisa comparar essas representações, não apenas a URL que aparece na barra do navegador.
A CVE-2025-29927 tornou conhecida uma falha de autorização no middleware. Em 2026, novos avisos envolvendo proxy e rotas de prefetch reforçaram a necessidade de analisar o fluxo completo. Este artigo propõe um roteiro ofensivo de autorização para ambientes sob teste, com casos negativos, evidências e critérios de reteste.
Como uma proteção contra recursão virou decisão de autorização
O postmortem do mantenedor explica o papel de x-middleware-subrequest: impedir recursão quando o middleware provoca novas requests. O erro de confiança aparece quando informação com essa finalidade interna é aceita de uma origem externa e influencia a decisão de executar o middleware.
O código abaixo é uma reconstrução didática dessa classe de erro, não a implementação de Next.js nem um payload do CVE. Ela torna visível por que o número de passagens informado pelo cliente não pode representar o estado real da execução.
function executarControle(entrada, contextoInterno) {
const passagens = contextoInterno?.passagens ?? 0;
if (!Number.isInteger(passagens) || passagens < 0) {
throw new Error('contexto invalido');
}
return { verificarAutorizacao: true, passagens };
}
const entrada = { passagens: 999, usuario: null };
const decisao = executarControle(entrada, { passagens: 0 });
if (!decisao.verificarAutorizacao || decisao.passagens !== 0) {
throw new Error('fronteira violada');
}
O dado externo não controla o contador. Ainda assim, atingir um limite interno deve produzir um comportamento explicitamente seguro, não conceder acesso a recursos. Contexto interno autenticado e autorização da operação são controles complementares, com finalidades diferentes.
No teste diferencial, registre em qual camada a decisão muda: CDN, servidor Next.js, middleware, matcher, renderização ou consulta. Headers e caminhos de prefetch podem selecionar transportes distintos para o mesmo recurso. Dois status diferentes não bastam; compare o objeto sensível retornado e a identidade que o backend usou na consulta.
Uma decisão próxima dos dados deve vincular sujeito, tenant e operação. O middleware pode rejeitar cedo, mas uma consulta como “pedido por ID” continua perigosa se não inclui a política correspondente. Repetir a matriz em HTML, RSC e API é o que diferencia uma correção arquitetural de uma regra que reconhece apenas uma variante de request.
A lição técnica da CVE-2025-29927
O aviso oficial de março de 2025 descreve a possibilidade de contornar verificações de autorização implementadas no middleware. Ele recomenda, como alternativa temporária à atualização, impedir que requests externas com x-middleware-subrequest cheguem à aplicação.
O ponto de análise é a fronteira de confiança de um header interno. Informação usada pelo framework para controlar processamento não deve ser aceita do cliente como justificativa para deixar de executar uma decisão de segurança.
O aviso registra versões historicamente corrigidas e proteção automática desse caso para hospedagens na Vercel. Essas condições são específicas daquele CVE. Não extrapole a proteção de um provedor para instalações próprias, para todos os proxies ou para os avisos posteriores.
Por que os casos de 2026 ampliam a matriz de testes
A release de maio de 2026 reuniu falhas de bypass, DoS, SSRF, cache poisoning e XSS. Entre os bypasses, os avisos documentam caminhos de segment-prefetch, tratamento de locale e parâmetros de rotas dinâmicas. Cada um tem pré-condições e intervalos de versão próprios.
O aviso de segment-prefetch no App Router, CVE-2026-44575, descreve variantes de transporte que podem alcançar uma página sem corresponder ao matcher previsto. Seu acompanhamento de correção incompleta informa que a primeira correção não se aplicava a middleware.ts com Turbopack. Passar no caso original não significa cobrir a variante descoberta depois.
Use a versão corrigida suportada no momento da implantação. Uma versão suficiente para bloquear o header de 2025 pode continuar afetada por outro caminho de 2026. Documente a versão real do build em vez de simplesmente anotar que o projeto foi atualizado.
Modele autorização por sujeito, objeto e operação
Considere uma aplicação fictícia de pedidos. Há um usuário do tenant Azul, outro do tenant Verde e um administrador. O objetivo é demonstrar se uma operação permitida para um sujeito continua recusada para os demais, independentemente da forma como a request chega ao backend.
Defina a decisão esperada antes de testar. Uma sessão válida não autoriza automaticamente acesso a outro tenant. Um identificador difícil de adivinhar também não substitui a política. O servidor precisa decidir quem pode ler ou modificar aquele objeto.
| Sujeito | Objeto | Operação | Decisão esperada |
|---|---|---|---|
| Sem sessão | Pedido privado Azul | Leitura | Recusar sem retornar os dados |
| Usuário Azul | Pedido Azul permitido | Leitura | Permitir |
| Usuário Verde | Pedido Azul | Leitura | Recusar |
| Usuário Azul comum | Pedido Azul | Operação administrativa | Recusar |
| Administrador autorizado | Pedido Azul | Operação administrativa | Permitir conforme a política |
A matriz serve de contrato para comparar HTML, dados de navegação e endpoints. Ela também revela quando uma proteção pertence somente à apresentação da página.
Compare as requests que o próprio cliente produz
No laboratório local, capture uma navegação legítima pelo painel de rede. Preserve método, rota, headers relevantes e tipo de resposta. Repita o caso removendo a sessão ou usando o usuário de outro tenant. Mude uma variável por vez e correlacione a resposta com os registros da decisão no servidor.
O exemplo abaixo faz apenas uma leitura de uma rota fictícia no loopback. Não contém uma reprodução automática dos CVEs:
curl --max-time 5 --path-as-is -sS -D resposta.headers \
http://127.0.0.1:3000/api/pedidos/pedido-azul-lab \
-o resposta.body
sha256sum resposta.body
Para a comparação autenticada, use credenciais sintéticas do laboratório por um arquivo local protegido. Não publique cookies ou bearer tokens no relatório. Grave hashes dos corpos e trechos mínimos que expliquem a diferença entre acesso permitido e recusado.
Quando houver Server Actions, use as requests reais dessa funcionalidade como base. Não invente um endpoint porque o nome parece plausível. O teste precisa exercitar uma operação existente, com seu formato e contexto próprios.
Normalize os caminhos sem perder a request original
Proxy, matcher e roteador podem interpretar uma mesma entrada de formas diferentes. Por isso, mantenha tanto o caminho original quanto a rota resolvida nos registros do laboratório. Variantes de locale, prefetch e parâmetros devem ser selecionadas conforme as funcionalidades realmente habilitadas.
Monte pares equivalentes de leitura e compare o objeto retornado. Uma resposta 200 de uma página pública de erro não é um bypass. Um redirect seguido automaticamente também pode esconder a primeira decisão. Registre a cadeia de respostas e analise o corpo antes de classificar o caso.
Desabilite o cache no reteste inicial ou identifique claramente suas entradas. Depois, teste o comportamento com cache, separando usuários e tenants. Um corpo de outro usuário pode representar uma falha de cache ou autorização; o diagnóstico exige seguir a origem dos dados.
A decisão deve existir junto do acesso aos dados
O guia de segurança de dados do Next.js recomenda uma camada de acesso a dados no servidor, com autorização e retornos mínimos. Middleware ou proxy podem rejeitar requests cedo, mas handlers e funções que expõem dados ainda precisam aplicar a política apropriada.
Na aplicação fictícia, a busca de um pedido deve incorporar o tenant autorizado e a operação, não apenas o ID recebido. Isso reduz a chance de um novo caminho de renderização reutilizar uma consulta desprotegida. A OWASP reforça negação por padrão e verificação de permissões a cada request.
Reteste o patch e a arquitetura
Depois da atualização, repita os casos associados aos avisos aplicáveis e toda a matriz de sujeitos. Confirme que leituras permitidas continuam funcionando e que recusas não incluem os dados protegidos. Para operações de escrita, verifique também o estado persistido, porque um erro de resposta pode ocorrer depois de uma mutação indevida.
O relatório deve identificar build, ambiente, router utilizado, intermediários, caso mínimo, objeto sintético e resultado. Diferencie bypass do middleware, autorização ausente no handler, vazamento de cache e hipótese sem comprovação.
A pergunta decisiva é simples: o servidor continua negando acesso ao mesmo objeto quando muda o caminho de transporte? Uma política consistente responde a essa pergunta em todas as representações do recurso.