Esta história começa quando Sébastien Lorber, mantenedor do Docusaurus, o projeto de documentação de código aberto baseado em React, percebe uma alteração de Pull Request no manifesto do pacote. Aqui está a mudança proposta para o popular pacote cliui npm:
Especificamente, chamando nossa atenção para a mudança nas dependências do npm que usam uma sintaxe desconhecida:
"dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
A maioria dos desenvolvedores esperaria ver um intervalo de versões semver no valor de um pacote ou talvez um Git ou URL baseado em arquivo. No entanto, neste caso, há uma sintaxe especial npm: prefix. O que isso significa?
O que é o alias do pacote npm?
O gerenciador de pacotes npm suporta um recurso de alias de pacote que permite a definição de regras de resolução personalizadas para pacotes. Dessa forma, onde quer que o pacote seja referenciado, por meio do código ou do arquivo de bloqueio, ele será resolvido para o nome e a versão especificados pelo alias.
Portanto, no caso da alteração proposta neste pull request, o pacote string-width-cjs será resolvido para o pacote string-width nas versões ^4.2.0. Isso significa que haverá uma entrada de diretório node_modules para string-width-cjs, mas com o conteúdo de string-width@^4.2.0 e comportamento semelhante no arquivo de bloqueio (package-lock.json).
O alias de pacote é um recurso do gerenciador de pacotes npm que pode ser usado em casos como suporte a ESM vs CJS.
Dito isso, o alias de pacote pode ser abusado. Em um artigo e divulgação de segurança que remonta a 2021, Nishant Jain, um Embaixador Snyk, demonstrou como o registro oficial do npmjs pode ser enganado para desinformar informações de dependência com base no alias de pacote como parte de uma confusão de dependência e preocupação de segurança da cadeia de suprimentos.
A solicitação pull foi benigna e não houve risco de um ataque à cadeia de suprimentos. No entanto, a preocupação de Sébastien com o nome do pacote levou à descoberta de um risco potencial à segurança.
Para examinar a solicitação pull, Sébastien empregou lockfile-lint. Essa ferramenta verifica arquivos de bloqueio como package-lock.json ou yarn.lock em busca de sinais de adulteração, garantindo que pacotes maliciosos não tenham sido injetados em vez do pacote npm original.
A execução da ferramenta mostrou os seguintes avisos:
npx lockfile-lint --path package-lock.json --allowed-hosts yarn npm --validate-https --validate-package-names detected resolved URL for package with a different name: string-width-cjs expected: string-width-cjs actual: string-width detected resolved URL for package with a different name: strip-ansi-cjs expected: strip-ansi-cjs actual: strip-ansi detected resolved URL for package with a different name: wrap-ansi-cjs expected: wrap-ansi-cjs actual: wrap-ansi ✖ Error: security issues detected!
Isenção de responsabilidade: lockfile-lint é uma ferramenta que desenvolvi em 2019 após minha publicação que divulgou a preocupação de segurança com lockfiles: por que npm lockfiles pode ser um ponto cego de segurança para injeção de módulos maliciosos.
Considerando os resultados do lockfile-lint acima, Sébastien pesquisou esses nomes de pacotes no npm e surpreendentemente descobriu que eles existem no registro público do npm:
Sébastien observou que esses nomes de pacotes não existem apenas no npm, mas também exibem características suspeitas. Os pacotes não estavam vinculados a um repositório de código-fonte público, estavam vazios de qualquer código real quando inspecionados e foram publicados anonimamente, sem qualquer informação pessoal associada.
Olhando para o pacote npm strip-ansi-cjs, não há um README ou um repositório de código-fonte. Existem, no entanto, muitos pacotes legítimos e populares que citam o mesmo comportamento.
Na verdade, este pacote em particular é popular, como podemos ver pelos seus 529 dependentes (outros pacotes que dependem deste) e 7.274 downloads semanais.
Observando o código de strip-ansi-cjs, mostra que há apenas um único arquivo neste pacote, o arquivo de manifesto do pacote package.json.
Então, por que um pacote que não faz nada recebe tantos downloads e por que tantos outros pacotes dependem dele?
Vamos inspecionar o autor desses pacotes npm.
Todos os três pacotes são propriedade de himanshutester002, e seus pacotes foram todos publicados no ano passado com números de versão programática. Algumas observações interessantes para destacar:
Você também pode observar que o usuário himanshutester002 não possui informações identificáveis nesta página de perfil de usuário no npmjs.
Observamos anteriormente que o pacote strip-ansi-cjs npm tem mais de 500 outros pacotes que o utilizam, portanto, é potencialmente um indicador positivo de popularidade. Vejamos eles:
Isto pode parecer credível devido à sua inclusão na lista, mas é mesmo?
Por exemplo, nomes como clazz-transformer ou react-native-multiply ou talvez gh-monoproject-cli parecem legítimos, mas serão?
Aqui está a página do pacote react-native-multiply npm:
Este pacote praticamente não tem downloads e seu autor é um usuário npm anônimo sem nenhuma informação identificável. O repositório de URL de origem para o qual este pacote redireciona é o inexistente https://github[.]com/hasandader/react-native-multiply. O perfil de usuário do GitHub também parece muito suspeito e carece de atividade prática.
Embora o pacote npm pareça conter código-fonte, uma análise mais detalhada revela que ele é um exemplo de código gerado para um protótipo de aplicativo “olá mundo”.
Você também deve se perguntar: se este pacote é apenas uma biblioteca de multiplicação, então por que ele precisa de 776 dependências para fazer o seguinte:
import { multiply } from 'react-native-multiply'; const result = await multiply(3, 7);
Embora algumas piadas sobre o JavaScript contribuir para uma árvore astronômica de pacotes aninhados por meio do uso excessivo de dependências, um projeto com 776 dependências diretas é excessivamente grande.
Entre todas essas dependências, estão os três pacotes npm suspeitos com os quais nossa história começou: string-width-cjs, strip-ansi-cjs e wrap-ansi-cjs:
Mencionamos que uma das dependências do strip-ansi-cjs foi chamada de clazz-transformer. Vejamos:
Vamos explicar o que está acontecendo aqui. O pacote npm clazz-transformer foi intencionalmente nomeado incorretamente com o título class-transformer em sua página README. Além disso, seu repositório de código-fonte, https://github[.]com/typestack/class-transformer, não se correlaciona com o nome do pacote, o que levanta preocupações sobre sua legitimidade.
O typstack/class-transformer do repositório associado no GitHub tem o arquivo package.json da seguinte maneira:
O arquivo package.json no GitHub não mostra nenhuma declaração de dependências, mas se inspecionarmos o código-fonte do pacote real no npmjs, veremos as 437 dependências com as quais este transformador clazz está empacotado. Novamente, eles agrupam de forma muito conveniente os três pacotes *-cjs suspeitos:
Antes de tirarmos mais conclusões, é importante mencionar algumas das características dos pacotes npm que observamos acima:
Nossos colegas da Sonatype identificaram anteriormente casos semelhantes de inundação de registros de código aberto com pacotes. Nesses casos, o objetivo final era que os desenvolvedores se recompensassem com tokens Tea, que é uma plataforma Web3 para monetizar software de código aberto.
Encontrar alguns arquivos tea.yaml nos pacotes mencionados apoia ainda mais a tese de que parte do propósito desta campanha é extrair tokens de Tea através do uso indevido de Tea.
No início deste ano, em 14 de abril de 2024, um usuário do fórum Tea postou um comentário que apoia ainda mais a preocupação com o abuso do chá:
Antes de entrar em contato com as conclusões, gostaria de agradecer sinceramente a Sébastien Lorber por sua mentalidade cautelosa de mantenedor e por ajudar a desvendar esses tópicos de um possível ataque à cadeia de suprimentos do NPM.
Neste ponto, tenho grande confiança de que posso continuar abrindo buracos no restante dos pacotes que são supostamente dependentes de string-width-cjs para encontrar indicadores muito duvidosos de legitimidade autêntica.
Suponho que todos esses pacotes dependentes e aumentos de download estão levando ao único propósito de criar falsa legitimidade para os pacotes 3 *-cjs, para que no devido tempo, com a vítima adequada em jogo, esses pacotes falsos sejam ser instalado e depois seguir com uma nova versão maliciosa.
Para ajudá-lo a se manter seguro ao trabalhar com software de código aberto, recomendo fortemente a adoção de práticas de segurança e, especificamente, destes recursos educacionais de acompanhamento:
Será que pegamos uma campanha de segurança da cadeia de suprimentos em meio ao seu crime, ou tudo isso é sobre a trilha de dinheiro e, como tal, pode ser atribuído a spam e abuso de registros públicos como npm e GitHub para minerar tokens de chá?
Independentemente de como isso aconteça, fique atento.
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3