Command injection in React Native Community CLI allows remote attackers to perform remote code execution by sending HTTP requests
Corrija agora. Ela está sob exploração confirmada pelo CISA e tem exploit funcional público.
Apply mitigations per vendor instructions, follow applicable BOD 22-01 guidance for cloud services, or discontinue use of the product if mitigations are unavailable.
Resumo
A falha está no endpoint /open-url do Metro Development Server, exposto pelo pacote @react-native-community/cli-server-api, que repassa sem validação o campo "url" de uma requisição POST para a função open() do npm, resultando em injeção de comando de SO (CWE-78). O problema se torna crítico porque o Metro, por padrão, faz bind em todas as interfaces de rede (não apenas localhost) e não exige autenticação — transformando algo que deveria ser um risco local de máquina de desenvolvedor em uma falha remota e não autenticada. Há exploração ativa confirmada (catálogo KEV da CISA, telemetria da VulnCheck desde dezembro/2025), o que justifica o CVSS 9.8 mesmo sendo uma falha em ferramenta de desenvolvimento, não em produção.
Detalhamento técnico
O endpoint /open-url do Metro dev server (parte de @react-native-community/cli-server-api) recebe um POST com corpo JSON contendo um campo "url". Esse valor é passado, sem sanitização, para a função open() do pacote npm "open", que internamente dispara um comando do sistema operacional para abrir a URL/arquivo com o handler padrão da plataforma. Por aceitar qualquer string — inclusive caminhos de executáveis locais e, em certas plataformas, argumentos de shell completos — a função vira um vetor de OS command injection (CWE-78).
O comportamento varia por plataforma. No Windows, open() aciona o shell (via cmd) para processar a string, o que dá ao atacante controle total de argumentos e permite executar qualquer comando de shell. Em macOS e Linux, open()/xdg-open tratam a entrada mais como caminho de arquivo/executável a ser aberto, então o atacante consegue rodar executáveis arbitrários mas com controle mais limitado sobre parâmetros — a JFrog nota que RCE completo nessas plataformas 'pode ser alcançável com pesquisa adicional', ou seja, não demonstrado publicamente até a análise deles.
Existe uma segunda falha, no código central do react-native (fora do cli-server-api), que faz o Metro bindar em 0.0.0.0 por padrão em vez de restringir a localhost. Essa combinação — endpoint vulnerável + bind em todas as interfaces — é o que eleva o risco de 'RCE local do próprio desenvolvedor' para 'RCE remoto não autenticado por qualquer host que alcance a porta do dev server'.
O fornecedor documenta que o impacto real difere por faixa de versão: entre 4.8.0 e 17.0.0, o atacante só consegue executar executáveis que já existem na máquina alvo, sem controle de argumentos (útil se combinado com outra técnica de upload de arquivo); a partir de 17.0.0 até 20.0.0-alpha.2, a falha permite RCE completo, com controle total de argumentos de shell no Windows.
Como é explorada
O vetor é uma requisição HTTP POST para /open-url no Metro dev server, sem qualquer autenticação. O único pré-requisito real é que o Metro esteja em execução (via npm start, npx react-native start/run-android/run-ios/run-windows/run-macos, ou equivalentes via @react-native-community/cli) e acessível pela rede — o que ocorre por padrão porque o servidor bind em todas as interfaces, não apenas em localhost. A porta usual é 8081. Qualquer atacante com alcance de rede a essa porta — rede local, VPN corporativa, ou internet se o servidor for exposto por engano — pode disparar a exploração sem interação do usuário.
A VulnCheck documentou exploração operacional ativa desde 21 de dezembro de 2025 via sua rede de canários, com payloads consistentes ao longo de semanas (repetidos em 04/01 e 21/01/2026), o que indica uso real e não apenas varredura ou teste de PoC. O padrão observado usa o campo "url" para injetar 'cmd /c powershell -EncodedCommand ', disparando um loader PowerShell multi-estágio que abre uma conexão TCP reversa, baixa um segundo estágio e o executa como processo — típico de estabelecimento de acesso inicial em máquinas Windows com o dev server exposto.
Desenvolvedores que usam frameworks que não dependem do Metro como dev server (ex.: alguns fluxos do Expo) tipicamente não estão expostos. O risco concentra-se em projetos iniciados sem framework via @react-native-community/cli, incluindo variantes para Windows e macOS.
Versões
Como se proteger
A correção do fornecedor está em @react-native-community/cli-server-api versão 20.0.0, que adiciona validação estrita de URL no middleware, rejeitando qualquer entrada cujo protocolo não seja http: ou https: antes de chamar open(). Como esse pacote é comumente empacotado junto com @react-native-community/cli em versões correspondentes, projetos usando @react-native-community/cli entre 4.8.0 e 20.0.0-alpha.2 provavelmente carregam a versão vulnerável — vale checar com 'npm list @react-native-community/cli-server-api' (local e global) em vez de assumir pela versão do cli principal.
Se a atualização não for viável de imediato, o paliativo real é iniciar o Metro explicitamente vinculado a localhost, usando a flag --host 127.0.0.1 (ex.: npx react-native start --host 127.0.0.1). Isso remove o vetor de rede remota, mas não corrige a injeção de comando em si — qualquer processo local na mesma máquina, ou um atacante que já tenha algum acesso à máquina do desenvolvedor, ainda pode explorar o endpoint. Também não protege ambientes onde outro serviço faz proxy ou redireciona tráfego externo para a porta do Metro.
Não funciona como mitigação apenas atualizar o pacote react-native ou @react-native-community/cli sem confirmar que cli-server-api foi de fato atualizado no lockfile — dependências fixadas (pinned) podem manter a versão vulnerável instalada mesmo após um 'npm update' superficial.
Como detectar
Procurar no log do Metro dev server (porta padrão 8081) requisições POST para o caminho /open-url com corpo JSON contendo o campo "url" com valores anômalos — não uma URL http/https legítima, mas strings iniciando com 'cmd /c', 'powershell', referências a .exe, ou caminhos de sistema. A VulnCheck documentou exploração real usando 'cmd /c powershell -EncodedCommand' seguido de um blob base64 longo, característico de loaders PowerShell multi-estágio.
Ausência desse padrão específico não garante ausência de tentativa de exploração: PoCs públicos alternativos e variações de payload (incluindo em macOS/Linux, onde o controle de argumentos é mais restrito) podem gerar corpos de requisição diferentes. Monitorar de forma mais confiável envolve alertar para qualquer POST não esperado em /open-url vindo de origem externa à rede de desenvolvimento, já que esse endpoint não deveria receber tráfego de fora do host do desenvolvedor em uso normal.