Zero-Day & Exploits
React2Shell: como auditar RSC e provar a correção da RCE
Da dependência vulnerável ao efeito comprovado: inventário de RSC, evidências de execução e reteste de React2Shell com atenção aos avisos de 2026.
React2Shell expôs uma fronteira que costuma ficar fora do inventário de um pentest: o código que transforma uma request em objetos e chamadas no servidor. Uma aplicação pode parecer uma interface JavaScript comum e, por baixo, expor um protocolo com capacidades muito diferentes das de um site estático.
A CVE-2025-55182, divulgada em 3 de dezembro de 2025, permite execução remota de código sem autenticação em versões afetadas dos pacotes de React Server Components. O aviso oficial do React atribuiu CVSS 10.0 à falha. Este guia organiza a análise ofensiva da superfície e a verificação de correções, sem confundir reconhecimento com exploração comprovada.
O patch público: propriedade própria e resolução de referências
Há código público para estudar a correção. No PR 35277 do React, o mantenedor aponta a ausência de verificações de propriedade própria como parte crítica da falha. O seguinte trecho curto é uma transcrição da condição exibida na revisão; o patch completo inclui outras mudanças e precisa ser analisado na versão correspondente.
Trecho real da correção: if (typeof value === 'object' && hasOwnProperty.call(value, name)) {. O acesso normal de JavaScript pode alcançar a cadeia de protótipos; já a verificação de propriedade própria exige que o campo pertença ao objeto em questão. Essa distinção limita referências a valores do modelo decodificado.
const herdado = { marcador: 'fora-do-modelo' };
const modelo = Object.create(herdado);
modelo.nome = 'Aurora';
function lerPropriedade(valor, chave) {
if (valor !== null && typeof valor === 'object'
&& Object.prototype.hasOwnProperty.call(valor, chave)) {
return valor[chave];
}
return undefined;
}
if (modelo.marcador !== 'fora-do-modelo') throw new Error('controle');
if (lerPropriedade(modelo, 'marcador') !== undefined) throw new Error('heranca');
if (lerPropriedade(modelo, 'nome') !== 'Aurora') throw new Error('legitimo');
Este segundo bloco é um exemplo original e não um exploit de React2Shell. Ele demonstra somente uma fronteira da correção: a mesma leitura é permitida para nome e recusada para um campo herdado. O controle de null pertence ao exemplo; não é uma transcrição adicional do patch.
A RCE requer mais que uma propriedade herdada. O decoder resolve referências e valores de um protocolo, e determinados valores alcançados podem interferir no processamento posterior. Para explicar uma cadeia real, siga entrada, resolução, objeto obtido e consumidor que o interpreta. Mostrar apenas a presença de constructor não demonstra execução no servidor.
Ao comparar builds, vincule a correção ao pacote efetivamente carregado. Uma busca textual por hasOwnProperty pode encontrar verificações em partes não relacionadas; não equivale a validar o caminho corrigido. Execute também o caso legítimo e a rejeição de referência fora do modelo no ambiente reproduzível. Essa combinação mostra a propriedade de segurança sem publicar uma cadeia operacional de RCE.
O que muda quando React passa a executar no servidor
React Server Components, ou RSC, não equivale a qualquer página feita com React. Um bundle que roda somente no navegador não oferece, por isso, o mesmo caminho vulnerável. O inventário precisa identificar o framework, o modo de renderização e os pacotes efetivamente carregados pelo processo de produção.
Server Functions permitem que uma interação do cliente gere uma chamada de rede para uma função no servidor. Antes de chegar à lógica de negócio, os argumentos passam por transporte e interpretação. A vulnerabilidade se encontra nessa fronteira de decodificação. Uma checagem escrita dentro da função não corrige um defeito do decoder que a precede.
Entrada HTTP controlada pelo cliente
↓
Transporte de Server Functions
↓
Decodificação pelo pacote RSC
↓
Autorização e lógica da aplicação
↓
Recursos disponíveis ao processo
O aviso original lista versões 19.0.0, 19.1.0, 19.1.1 e 19.2.0 de react-server-dom-webpack, react-server-dom-parcel e react-server-dom-turbopack. Também esclarece que o suporte a RSC pode manter a exposição mesmo sem Server Functions explicitamente criadas pela equipe.
Um fingerprint é uma pista, não um finding de RCE
O primeiro objetivo do operador é ligar três evidências: componente vulnerável, caminho alcançável e efeito observado. Identificar um header, um formato de resposta ou um nome de arquivo é útil para orientar o trabalho, mas não demonstra execução remota. Um intermediário pode reproduzir headers antigos, e uma instalação pode carregar versões diferentes das que aparecem no repositório.
Comece pelo material fornecido pelo responsável: lockfile, manifesto da imagem, digest implantado e árvore de dependências. No checkout correspondente ao artefato, uma consulta local ajuda a encontrar dependências diretas e transitivas:
npm ls next react react-dom react-server-dom-webpack react-server-dom-parcel react-server-dom-turbopack --all
npm explain react-server-dom-webpack
Ausência de um pacote na lista só é conclusiva quando o checkout representa o build em execução. Para imagens antigas, plugins de bundler e monorepos, confronte também o conteúdo do artefato. Registre versão e origem de cada cópia encontrada; atualizar apenas a dependência da raiz pode deixar outro pacote vulnerável acessível.
Defina a prova antes de enviar o teste
Em uma avaliação autorizada, combine uma evidência inofensiva e limites operacionais antes de reproduzir a falha. A finalidade é demonstrar a fronteira atravessada com o menor efeito necessário. Não é preciso acessar credenciais, instalar software ou criar persistência para provar impacto no processo.
Uma reprodução controlada pode usar um marcador aleatório exclusivo da execução e observação local no container descartável. Correlacione request, horário, versão, imagem e resultado. O marcador precisa estar ausente antes do teste e não pode aparecer apenas porque o próprio payload foi registrado em um log.
| Evidência | Conclusão possível | O que falta |
|---|---|---|
| Pacote e versão afetados no artefato | Dependência vulnerável presente | Alcançabilidade do caminho em produção |
| Resposta compatível com RSC | Superfície compatível observada | Versão real e comportamento do decoder |
| Erro 500 após uma request | Falha de processamento | Evidência específica de execução |
| Marcador independente produzido pelo processo no laboratório | Efeito reproduzido no ambiente documentado | Correspondência com o build avaliado |
| Teste deixa de produzir o marcador após correção | Regressão do caso reproduzido corrigida | Cobertura de outras variantes e funções |
Essa classificação evita dois erros comuns: publicar uma RCE com base em um erro genérico e declarar a aplicação segura porque uma única assinatura de scanner não disparou.
O laboratório deve preservar a cadeia de comparação
Use uma aplicação fictícia, dados sintéticos e duas imagens identificadas por digest: uma representando o caso estudado e outra com a correção. Mantenha as mesmas rotas, configurações e dependências periféricas. Se mudar vários componentes ao mesmo tempo, o resultado perde força para explicar qual alteração interrompeu o comportamento.
Para cada execução, guarde método, rota, tipo de conteúdo, hash do corpo de teste, identificador de correlação e observação do processo. No reteste, confirme também que uma interação legítima continua funcionando. Uma aplicação que deixou de responder a qualquer request não comprova correção funcional.
O roteiro é uma proposta de laboratório, não uma afirmação de que este site ou qualquer serviço público foi explorado. A comprovação exige observação no ambiente específico; a mera instalação do framework não resolve essa etapa.
Corrigir a RCE inicial não encerra o acompanhamento
O comunicado posterior do React, atualizado em janeiro de 2026, distinguiu negação de serviço e exposição de código da RCE original. Ele informa que a correção de React2Shell continuava efetiva contra aquela RCE, mas que novas falhas exigiam outras atualizações. Não trate todos esses CVEs como uma única capacidade de execução.
Em maio de 2026, a release coordenada de segurança do Next.js incluiu outra falha de DoS em RSC, CVE-2026-23870. Esses avisos têm datas e escopos próprios. As primeiras versões que corrigiram a CVE de dezembro são referências históricas, não uma recomendação suficiente de versão para outubro de 2026.
Selecione a versão suportada e corrigida para a linha usada pela aplicação, consultando os avisos atuais do mantenedor. Recrie o artefato, confirme o digest implantado e repita a consulta de dependências. Uma alteração no arquivo de configuração que não chega ao processo não reduz a exposição real.
O impacto depende também dos privilégios do processo
Depois de comprovar o comportamento, avalie quais recursos o processo pode acessar usando o inventário autorizado. Usuário sem privilégios, credenciais com escopo reduzido, sistema de arquivos restrito e limites de saída de rede ajudam a conter consequências. São controles de impacto; não substituem a atualização do componente vulnerável.
A documentação de Server Functions orienta tratar argumentos como entrada não confiável e autorizar mutações. A revisão da função deve considerar sessão, tenant, objeto e operação. Isso cobre uma fronteira diferente da desserialização e continua necessário depois do patch.
Como entregar um relatório tecnicamente defensável
Separe componente afetado, superfície observada, efeito reproduzido e limitações. Anexe a identificação do build, o caso mínimo, a comparação antes/depois e a funcionalidade legítima usada no reteste. Se não houve observação de execução, escreva isso com clareza.
O resultado mais útil é uma cadeia reproduzível de evidências. Ela permite que desenvolvimento, operação e segurança verifiquem a mesma correção, sem depender de uma captura de tela ou de um selo vermelho de ferramenta.