Fim do ciclo de vida do RequireJS: riscos do carregador AMD e suporte à segurança

Os patches do php2shell (CVE-2026-109618 e CVE-2026-109619) para o PHP em fim de vida (EOL) já estão disponíveis. Como as respostas do atendimento de vendas estão mais demoradas do que o normal devido à alta demanda, a maneira mais rápida de obter os pacotes corrigidos é adquirir o ELS para Runtimes on-line (abre em uma nova aba). Leia as perguntas frequentes sobre os patches

Vá direto para um resumo gerado por IA desta postagem do blog

  • Resuma esta postagem com o Perplexity
  • Resuma esta postagem com o Gemini

Principais conclusões

  • O RequireJS é um projeto arquivado do OpenJS; portanto, nenhum mantenedor do projeto original está comprometido em corrigir vulnerabilidades futuras.
  • A migração para os módulos ES envolve definições de módulos, comportamento de carregamento, otimização de compilação, testes e implantação.
  • A vulnerabilidade CVE-2024-38999 é classificada como variando de Média a Crítica, dependendo da fonte; portanto, a acessibilidade é mais importante.
  • No Magento e no Moodle, o RequireJS já vem integrado à plataforma; portanto, abandonar o AMD é um projeto que envolve toda a plataforma.

O RequireJS ajudou grandes aplicativos de navegador a se tornarem modulares antes mesmo da existência dos módulos ES nativos. O desenvolvimento ativo foi encerrado há anos, e isso não seria nada de mais, não fosse o fato de que os carregadores AMD ainda estão presentes em grande parte do código front-end corporativo, muitas vezes em plataformas nas quais não é possível substituir o carregador.

Esta publicação aborda o que significa o fim do ciclo de vida para um carregador como o RequireJS, como lidar com um CVE de destaque com pontuações de gravidade extremamente inconsistentes e por que abandonar o AMD é um projeto de arquitetura, e não apenas uma atualização de dependências.

O RequireJS resolveu a questão do JavaScript modular antes mesmo do navegador fazer isso

Em algum lugar da sua organização, provavelmente há um front-end que ainda é inicializado por meio de um data-main atributo, e ninguém da equipe atual o escreveu. Ele vem carregando normalmente há cerca de uma década, e esse é o problema.

O RequireJS surgiu quando os navegadores ainda não possuíam uma maneira nativa de dividir o JavaScript em módulos e carregá-los sob demanda. Ele implementou o AMD, o formato de Definição Assíncrona de Módulos, para que grandes bases de código pudessem declarar dependências explicitamente e carregá-las em paralelo, em vez de concatenar tudo em um único arquivo e torcer para que a ordem fosse mantida. Para equipes que enviam centenas de milhares de linhas de código para o navegador em 2013, essa estrutura era a diferença entre um aplicativo sustentável e um emaranhado de variáveis globais.

Ainda é possível encontrá-lo em alguns lugares específicos. Uma loja virtual no Magento 2. Uma implantação do Moodle. Um aplicativo Backbone ou Knockout da época de 2015. Uma ferramenta interna de relatórios integrada com data-main que ninguém abriu desde que a pessoa que o construiu foi embora.

Nada está com defeito, ninguém está fazendo manutenção ativa nisso e a arquitetura subjacente não permite uma correção pontual e precisa. Não dá para contornar uma decisão arquitetônica com remendos.

O RequireJS ainda recebe manutenção?

Não é algo em que se deva basear um plano de suporte, e a classificação é oficial. A OpenJS Foundation lista o RequireJS como um projeto arquivado, ao lado de outras bibliotecas que chegaram ao fim de sua vida útil, como jQuery Mobile, jQuery UI, Sizzle e o Polyfill de Pointer Events.

O repositório continua público e o pacote npm ainda pode ser instalado, mas o status “Arquivado” não dá motivos para esperar que alguém do desenvolvedor original responda quando o próximo aviso for publicado.

Você sabia? O RequireJS lançou a versão 2.3.8 em 30 de novembro de 2025, mais de cinco anos depois que o OpenJS o incluiu pela primeira vez em sua lista de produtos em fim de vida. Portanto, essa classificação não significa que o código esteja congelado. Significa que ninguém se comprometeu a mantê-lo, e isso é algo bem diferente.

A AMD resolveu o problema do carregamento de módulos no navegador antes mesmo que a plataforma tivesse uma solução, e os módulos ES nativos, juntamente com os empacotadores modernos, acabaram assumindo toda a função para a qual o projeto havia sido criado. O projeto chegou até a ser solicitado publicamente a informar seu status em sua própria página inicial. Essa página ainda indica a versão 2.3.7 como a mais recente e não faz nenhuma menção ao rótulo “Arquivado”.

Analisando um CVE com três níveis de gravidade diferentes

CVE-2024-38999 é o resultado que aparece nas verificações do RequireJS. Trata-se de um bug de poluição de protótipos em s.contexts._.configure que afeta todas as versões até a 2.3.6, e cuja correção foi lançada na versão 2.3.7, em julho de 2024.

Agora veja como os bancos de dados classificam o mesmo bug.

Fonte CVSS Gravidade
NVD (NIST) Nenhuma pontuação atribuída Não enriquecido
CISA-ADP 10,0 (v3.1) Crítico
Viável 9.3 (v4.0) Crítico
Aviso do GitHub 8,9 (v4.0) Alto
Snyk 6,9 (v4.0) Médio

A diferença parece enorme, mas grande parte dela decorre da mecânica de pontuação, e não de qualquer divergência real sobre o bug. A pontuação de 10,0 da CISA-ADP segue o CVSS v3.1. A pontuação de 9,3 da Tenable e a de 8,9 do GitHub compartilham as mesmas métricas básicas do CVSS v4.0, e a pontuação mais baixa do GitHub decorre da inclusão da métrica de ameaça “Maturidade da Exploração” no nível “Prova de Conceito” (E:P). O verdadeiro outlier é a classificação “Médio” da Snyk, que se baseia em uma avaliação de impacto muito menor.

A pontuação EPSS do CVE é de cerca de 0,76% (0,0076 na escala de 0 a 1, em 14 de setembro de 2026); portanto, o modelo estima que a probabilidade de exploração nos próximos 30 dias seja inferior a 1%. Ele ainda se situa na faixa intermediária entre todos os CVEs avaliados (53º percentil), mas esse percentil é uma classificação em relação a outros CVEs, não uma probabilidade.

Parte da confusão se deve à forma como o registro foi tratado. O NVD ainda lista o CVE-2024-38999 como “Adiado”, de modo que cada banco de dados a jusante aplicou seus próprios critérios de pontuação a um registro que o NVD nunca analisou. O RequireJS também recebeu um segundo relatório de contaminação de protótipos no mesmo período. Esse, o CVE-2024-38998, tinha como alvo a função `config` e foi rejeitado em janeiro de 2025, após a CNA concluir que não se tratava de um problema de segurança.

Para a triagem, a pontuação é apenas um dos critérios, e a acessibilidade merece mais peso do que o número em si. Os dados controlados por invasores podem acessar o objeto que seu aplicativo passa para requirejs.config()? É esse chamado que alimenta s.contexts._.configure. Se a resposta for não, o risco prático é baixo, independentemente da cor do crachá.

Atenção: uma pontuação contestada não remove a constatação do seu relatório. “Achamos que essa pontuação está superestimada” é uma opinião, não uma correção.

Na prática, se o CVE constar no seu relatório e você não puder migrar para uma versão corrigida, será necessário apresentar uma compilação corrigida ou uma declaração por escrito sobre a vulnerabilidade. Um argumento relacionado ao CVSS não se enquadra em nenhuma dessas opções.

A escolha de uma alternativa ao RequireJS é uma decisão de arquitetura

Trocar o RequireJS por algo mais recente parece uma mudança de dependência. É mais parecido com decidir como sua aplicação carrega o código.

Existem quatro destinos possíveis, e eles não são equivalentes. Os módulos ES nativos permitem que o navegador ou o ambiente de execução cuidem do carregamento, e o RequireJS desaparece completamente. Os módulos gerenciados por um bundler repassam o gráfico de módulos para o webpack, o Vite ou o esbuild, que o resolvem no momento da compilação e geram uma saída otimizada. Adaptadores incrementais e shims de interoperabilidade permitem que os módulos AMD e ES coexistam durante uma longa migração. E o carregamento de scripts simples ainda é uma necessidade real em alguns ambientes mais antigos ou restritos.

Por trás dessas quatro questões, há uma que é fácil deixar passar despercebida. O aplicativo ainda precisa do carregamento de módulos em tempo de execução, ou isso era uma limitação da época em que foi desenvolvido? Grande parte da arquitetura da AMD existe simplesmente porque os navegadores de 2013 não ofereciam alternativa.

Além disso, há as suposições embutidas no próprio código, e é aí que as estimativas dão errado. Espere encontrar definições de módulos nomeados e anônimos misturadas na mesma árvore, prefixos de plug-ins como text! para carregar modelos e aliases definidos em paths, e shim entradas para variáveis globais que não são da AMD. Espere encontrar dependências circulares que o carregador por acaso tolerou, variáveis globais encapsuladas como módulos para parecerem modulares sem realmente serem, e configurações do otimizador que geram pacotes específicos para cada implantação.

Dica de quem conhece: Faça uma busca no código-fonte por text!, shim, e paths antes de definir o escopo de qualquer coisa. Esses três padrões prevêem melhor as dificuldades da migração do que a contagem bruta de arquivos, pois cada um deles reflete um comportamento em tempo de execução que um empacotador não consegue reproduzir automaticamente.

Escolha o destino antes que alguém comece a trabalhar no código. A conversão para módulos ES e a reprodução de um layout de artefatos do otimizador são projetos distintos, com orçamentos diferentes.

Por que a conversão automatizada só leva você até certo ponto

Os codemods e as transformações do jscodeshift existem de verdade e realmente alteram a sintaxe. Para módulos estáticos simples, um define([...], function(){}) o bloco passa a ser import declarações sem muito drama. O problema é que a sintaxe nunca foi a parte difícil.

As suposições de tempo de execução não se transformam. A ordem de carregamento e os efeitos colaterais podem mudar no momento em que os módulos são resolvidos de maneira diferente, e um aplicativo que dependia de uma sequência de carregamento AMD específica pode apresentar falhas que a análise estática não detecta. Os testes costumam estar diretamente vinculados à configuração do RequireJS, de modo que falham por motivos não relacionados ao código em teste. As implantações em produção podem esperar um layout de artefatos otimizado específico que um novo empacotador simplesmente não produz. E nomes de módulos dinâmicos — aqueles montados a partir de variáveis em tempo de execução —, por definição, resistem à análise estática.

Depois, há a “armadilha da plataforma”, que é exatamente onde se insere uma implantação do Magento ou do Moodle. Nessas plataformas, o RequireJS faz parte da arquitetura front-end. Geralmente, é possível ampliar sua configuração (os módulos e temas do Magento vêm com seus próprios requirejs-config.js arquivos, por exemplo), mas a substituição do próprio carregador está limitada ao que a versão da plataforma suporta.

Da prática: Imagine um varejista com uma instalação do Magento altamente personalizada, com cerca de 30 módulos personalizados do RequireJS e um tema que substitui partes da configuração do carregador da plataforma. Uma atualização da plataforma pode trazer uma versão mais recente do RequireJS incluída no pacote, mas o site da loja continua sendo inicializado via AMD depois disso. Abandonar o RequireJS nesse caso depende tanto do roteiro de desenvolvimento da plataforma quanto do seu, e nenhum codemod faz alterações nisso.

Portanto, comece com um exercício de contagem antes de qualquer estimativa. Conte os arquivos. Conte as entradas do shim. Determine qual parte da configuração do carregador é sua e qual parte pertence à plataforma. Essas três respostas definem praticamente tudo o que vem a seguir, e a última delas determina se a migração está, de fato, sob seu controle.

Um plano gradual da AMD para os módulos modernos

Quando uma migração está em pauta, implementá-la em etapas é quase sempre melhor do que uma reescrita radical de uma só vez. A ordem que costuma dar certo na produção começa com o mapeamento do gráfico de módulos, para que você saiba o que depende do quê. A partir daí, converta primeiro os módulos finais e outros limites de baixo risco, e introduza camadas de compatibilidade de forma planejada, em vez de por acaso, quando algo deixar de funcionar. Converta os testes junto com os módulos de produção que eles cobrem, e não depois. Avalie o tamanho do pacote e o comportamento de carregamento após cada etapa e remova os shims somente depois que todos os que os utilizam tiverem sido eliminados.

Cada etapa deve deixar o aplicativo pronto para ser lançado. O objetivo da ordenação “leaf-first” é que um módulo de baixo risco possa ser revertido de forma limpa caso o comportamento de carregamento mude, o que não é possível com um módulo que tenha muitas dependências.

Dica profissional: Quando a arquitetura permitir, execute a compilação antiga do RequireJS e a nova compilação do bundler em paralelo, por meio de um sinalizador de recurso, durante a conversão, e compare a cascata de rede entre as duas antes de remover o carregador antigo. Uma mudança na ordem das solicitações costuma ser o primeiro indício de que um efeito colateral foi deslocado.

No entanto, nem todo aplicativo se encaixa nesse caminho. A decisão correta depende de quem é o responsável pela compilação e do grau de “congelamento” do artefato. Com uma base de código pequena e controle total sobre a compilação, converta para módulos ES e pronto. Quando a plataforma é responsável pelo carregador, aplique o patch no local e inclua a atualização da plataforma em um roteiro com prazos definidos. Para um artefato “congelado” ou requisitos de ambiente isolado, aplique o patch no local e documente a vulnerabilidade para o auditor.

Quando o carregador existente ainda precisa de proteção

Às vezes, a migração não está nos planos para este trimestre, e o carregador ainda precisa estar seguro nesse meio tempo. Isso costuma acontecer em portais corporativos de longa duração, consoles administrativos integrados e produtos com janelas de atualização controladas. Também ocorre em aplicativos que estão sendo substituídos, em vez de modernizados, e em sistemas cuja cobertura de testes de regressão ainda não permite a migração do carregador.

Tenha uma visão realista sobre o limite. A atualização para a versão 2.3.7 ou a atual 2.3.8 corrige a vulnerabilidade CVE-2024-38999, mas isso é o máximo que o upstream permite. Nada indica que haverá uma versão 2.4. Não há compromisso de manutenção por trás do próximo comunicado, nem tempo de resposta garantido caso ele seja publicado.

A realidade: atualizar para a versão mais recente do RequireJS não significa que o software tenha suporte. Uma versão corrigida hoje não garante nada em relação a uma vulnerabilidade que venha a ser relatada no ano que vem.

O Suporte de Ciclo de Vida Ilimitado (ELS) da TuxCare para o RequireJS abrange as versões 2.1.22 e 2.3.6, fornecidas como pacotes npm a partir do registro hospedado pela TuxCare, com documentos SBOM e VEX e metas de resposta vinculadas à gravidade do CVSS. Trata-se de um trabalho de gestão, e não de desenvolvimento upstream. A equipe verifica se cada novo CVE se aplica às versões cobertas, faz o backport da correção e testa cada compilação quanto à integridade, funcionalidade e regressões antes de lançá-la, para que o código existente continue funcionando da mesma forma que funciona hoje. Essa última parte é importante para um carregador cujo comportamento não pode mudar. É parte do suporte mais amplo da TuxCare a bibliotecas em fim de vida útil (EOL) para equipes que dependem de componentes cujo desenvolvimento original já os deixou para trás.

Sustentabilidade do OpenJS após o término da fase ativa de um projeto

O fato de o RequireJS ser um projeto arquivado do OpenJS não significa o fim de sua história em termos de segurança. O Programa de Sustentabilidade do Ecossistema da Fundação existe justamente para que versões arquivadas, em fim de vida útil (EOL) e mais antigas possam receber serviços comerciais de segurança, com uma parte da receita revertida para a Fundação e seus projetos. A TuxCare é membro Gold e prestadora de serviços nesse programa, e seus patches permanecem na cadeia de distribuição. Eles não se tornam versões oficiais do RequireJS.

Portanto, considere o RequireJS como parte da arquitetura que mantém o front-end integrado, pois é exatamente isso que ele é. Excluí-lo numa sexta-feira à tarde não vai dar certo, e substituí-lo merece mais do que uma simples troca apressada de pacotes.

Resumo
Fim do ciclo de vida do RequireJS: riscos do carregador AMD e suporte à segurança
Nome do artigo
Fim do ciclo de vida do RequireJS: riscos do carregador AMD e suporte à segurança
Descrição
O RequireJS é um projeto arquivado do OpenJS, sem compromisso de manutenção. Saiba o que o EOL significa para front-ends AMD e quais são suas opções de suporte.
Autor
Nome da editora
TuxCare
Logotipo da editora

Junte-se a mais de 4.500 profissionais de Linux e código aberto!

2 vezes por mês. Sem spam.

Índice
Obtenha as respostas sobre segurança de código aberto de que você precisa

Junte-se a mais de 4.500 profissionais de Linux e código aberto!

2 vezes por mês. Sem spam.