Mais 123% CVE comunicadas por dia em 2026 do que no ano passado.

Cadeia de abastecimento

O que é a confusão de dependências?

A confusão de dependências é um ataque em que um build instala o pacote público de um atacante em vez do seu pacote privado com o mesmo nome. Ninguém comete um erro de escrita. Basta ao atacante descobrir o nome de um pacote interno e publicá-lo num registo público com um número de versão alto, e um build mal configurado faz o resto.

Atualizado a

Como funciona um ataque de confusão de dependências

  1. Encontrar um nome interno. Os nomes de pacotes privados são expostos através de código público, bundles de JavaScript, mensagens de erro e manifestos deixados em repositórios.
  2. Publicar o mesmo nome publicamente. O atacante regista-o no npm, no PyPI ou noutro registo público, com um número de versão muito alto.
  3. Esperar por um build. Um gestor de pacotes configurado para consultar tanto o registo interno como o público encontra dois candidatos e prefere a versão mais alta.
  4. Executar dentro da empresa. O script de instalação do pacote é executado na máquina de um programador ou num runner de CI, com acesso a tudo o que lá estiver.

A investigação que lhe deu nome

Em fevereiro de 2021, o investigador de segurança Alex Birsan publicou a técnica. Tinha-a usado para executar código em mais de 35 organizações, entre elas a Apple, a Microsoft e o PayPal, ao abrigo de programas de bug bounty ou com autorização. Funcionou nas três linguagens que testou, e os atacantes começaram a copiá-la poucos dias depois da publicação.

Porque acontece

A causa principal é um gestor de pacotes que trata vários registos como equivalentes. O exemplo clássico é o Python: a opção --extra-index-url do pip acrescenta uma segunda origem junto ao PyPI, e o pip pode instalar o pacote público se encontrar um com o mesmo nome.

# Unsafe for private packages: both indexes are candidates
pip install --extra-index-url https://pypi.internal.example/simple my-internal-lib

# Safer: one index you control, which proxies public packages
pip install --index-url https://pypi.internal.example/simple my-internal-lib

O npm tem o mesmo problema com nomes internos sem scope, ao passo que um scope associado ao seu registo o evita.

# .npmrc: everything under @acme comes only from your registry
@acme:registry=https://npm.internal.example/

Como evitar a confusão de dependências

  • Use uma única fonte de verdade. Aponte os builds para um único registo interno que faça de proxy dos pacotes públicos e configure-o para que os nomes internos nunca sejam resolvidos publicamente.
  • Use scopes ou namespaces. Seja dono de um scope como @acme no registo público e associe-o ao seu registo privado.
  • Reserve os seus nomes. Registe os nomes dos pacotes internos em registos públicos, para que mais ninguém o possa fazer.
  • Bloqueie e verifique. Faça commit de um lockfile e use a verificação de hashes, como o --require-hashes do pip, para que um pacote diferente faça a instalação falhar. Consulte o que um lockfile faz e não faz.
  • Limite a que os builds se podem ligar. Se um build só conseguir alcançar o seu registo, não pode obter de todo o pacote do atacante. Consulte a política de egress do GitHub Actions.
  • Verifique o que expõe. Procure os nomes dos seus pacotes internos em código público e em bundles de cliente.

Confusão de dependências vs typosquatting

O typosquatting depende de uma pessoa escrever mal o nome de um pacote público. A confusão de dependências usa o nome exato de um pacote privado e depende da forma como o build está configurado. Ambos chegam ao mesmo ponto: código do atacante a ser executado no seu build. Consulte o que é um ataque à cadeia de abastecimento para ver como se relacionam com outros ataques.

Como saber se foi afetado

Procure nomes de pacotes internos que tenham sido resolvidos a partir de um registo público, ou versões que não existam no seu registo interno. Isso é difícil de fazer apenas com um lockfile, porque a questão é de onde veio efetivamente um pacote durante o build.

Como o CRACI ajuda

O CRACI atua no ponto em que o pacote é obtido. Como seu runner de GitHub Actions, aplica uma política de egress com origens tipificadas para registos, pelo que um build pode ser limitado aos registos que permite. Regista também cada pacote que cada job obteve numa SBOM, para que possa ver o que entrou num build. O CRACI não deteta que um pacote é malicioso, pelo que deve manter a configuração do seu registo como primeira linha de defesa. Consulte as boas práticas de segurança da cadeia de abastecimento de software.

Confusão de dependências: perguntas frequentes

O que é um ataque de confusão de dependências?

Um ataque em que um pacote público com o mesmo nome de um privado é instalado por engano, porque o gestor de pacotes consulta ambos os registos e prefere a versão mais alta.

Em que é que a confusão de dependências difere do typosquatting?

O typosquatting depende de alguém escrever mal o nome de um pacote público. A confusão de dependências usa o nome exato de um pacote privado e depende de uma configuração de build que consulta registos públicos.

Como evitar a confusão de dependências?

Use um único registo interno, nomes de pacotes com scope, lockfiles com verificação de hashes e regras que limitem os registos que os seus builds podem alcançar. Reservar publicamente os seus nomes internos também ajuda.

O --extra-index-url é seguro?

Não para pacotes privados. Torna ambos os índices candidatos, pelo que pode ser instalado um pacote público com o mesmo nome. Use --index-url com um único índice que controle.

Quem descobriu a confusão de dependências?

O investigador de segurança Alex Birsan publicou a técnica em fevereiro de 2021, depois de a usar contra mais de 35 organizações ao abrigo de programas de bug bounty ou com autorização.

Limite de onde os seus builds podem obter pacotes

Permita apenas os registos de que um job de GitHub Actions precisa e veja cada pacote que ele trouxe.

Marcar demo