Aikido

O Fork Desperta: Por que as Redes Invisíveis do GitHub Quebram a Segurança de Pacotes

Escrito por
Charlie Eriksen

Prezado GitHub,

A questão é a seguinte; há um problema de segurança que tem sido um segredo aberto há algum tempo. As pessoas falam sobre isso em issue trackers. Isso aparece em divulgações de segurança. É discutido em threads do Slack que inevitavelmente terminam com "...mas precisaríamos que o GitHub realmente expusesse esses dados.

Estou chamando a atenção de vocês para isso porque estou cansado de ver essa conversa terminar sempre da mesma forma. A comunidade de segurança está apenas pedindo visibilidade sobre os dados que vocês já possuem. Sem isso, estamos presos. Registries de pacotes não conseguem alertar os usuários. Ferramentas de segurança não conseguem sinalizar referências suspeitas. Os atacantes, enquanto isso, entendem perfeitamente esse ponto cego. Eles já estão explorando-o, assim como Shai Hulud fez.

Estamos nos aproximando do período de festas. E gosto de pensar que fui bem comportado este ano. Meu único desejo é que vocês nos deem as ferramentas para proteger melhor o ecossistema. Espero que não seja pedir demais!

Qual é a questão?

Gerenciadores de pacotes como o seu próprio npm, juntamente com terceiros como Bun e PyPI, permitem que desenvolvedores instalem um repositório GitHub diretamente como uma dependência. Seu próprio GitHub Actions depende dessa mesma primitiva.

npm install github:trusted-org/trusted-package#commit-sha

bun install github:trusted-org/trusted-package#commit-sha‍

pip install git+https://github.com/trusted-org/trusted-package#commit
- uses: trusted-org/trusted-package@commit-sha

A maioria das pessoas olharia para isso e pensaria: "Onde está o problema de segurança? Estou literalmente especificando o repositório exato."

É. Eu pensei o mesmo.

Mas o que acontece é o seguinte: se aquele commit SHA existir em um fork do repositório, você puxará o código do fork. Não do repositório na sua URL. Do fork. Mas que diabos?

Deixe isso assentar por um segundo. Eu espero…. A URL diz trusted-org/trusted-package. Mas se um atacante fez um fork daquele repositório, adicionou um commit malicioso e conseguiu que você referenciasse o SHA daquele commit, você acabou de instalar o código deles. Não o código que você imaginou. Não o repositório que você especificou. O deles.

Por que isso acontece?

Isso acontece por causa da "Fork Network" do GitHub.

É provável que você nunca tenha ouvido falar disso. A questão é a seguinte: quando você faz um fork de um repositório, você não obtém uma cópia totalmente independente. Seu fork se junta a uma rede, compartilhando o armazenamento de objetos git subjacente com o original e todos os outros forks. É assim que o GitHub lida com a escala. Eles não estão armazenando um milhão de cópias dos mesmos commits. Faz sentido.

É também por isso que este ataque funciona.

Os comandos acima, em última análise, atingem o "Baixar um arquivo de repositório (tar)" endpoint. A documentação diz o seguinte sobre o owner parâmetro:

O parâmetro owner é apenas o proprietário do repositório, não garante que seja código daquele próprio repositório

Não há garantias de que o código pertença diretamente ao repositório, nem avisos sobre a possibilidade de ele ser puxado de um fork. Honestamente? Dada a arquitetura, este comportamento faz sentido. O commit existe no grafo compartilhado. O GitHub o serve. Isso não está errado.

O que é o problema é que isso cria uma ambiguidade que ninguém mais consegue decifrar. Você solicita trusted-org. Você recebe código de um atacante. O GitHub atendeu à sua solicitação. Você simplesmente não obteve o que pensava estar pedindo. E nenhuma ferramenta fora do GitHub consegue identificar a diferença.

A assimetria 

Olha, nós realmente apreciamos quando você adicionou aquele banner de aviso no GitHub.com. Ver um aviso para commits como esses? Isso é útil. Mostra que você sabe que este é um problema que merece ser exposto.

Mas a questão é a seguinte: gerenciadores de pacotes não consultam seu website. Eles chamam sua API. E a API não lhes dá nenhuma indicação de que algo incomum está acontecendo. Nenhuma flag, nenhum metadado, nada documentado. Assim, o npm não pode avisar os usuários. O PyPI não pode avisar os usuários. O Bun não pode avisar os usuários. A informação existe. Você já a está expondo no frontend. Mas o ecossistema não consegue acessá-la.

Por que não?

Hora de ser rigoroso

Lembra daquele endpoint "Download a repository archive (tar)" que mencionamos? Atualmente, ele é o elo mais fraco. Mas também é o lugar óbvio para corrigir isso.

Aqui está uma ideia: adicione um rigoroso parâmetro. Quando definido, a requisição falha se o commit existir apenas em um fork, e não no repositório real especificado. Gerenciadores de pacotes optam por isso, todos os outros mantêm o comportamento atual, nada quebra.

Vocês já estão fazendo essa verificação no frontend para aquele banner de aviso. Basta dar à API a mesma capacidade. É claro que seria ideal se vocês pudessem expor mais informações da rede de forks na API em geral, mas isso pelo menos resolve o problema mais óbvio.

Boas festas!

Não estou escrevendo isso como uma reclamação. Estou escrevendo porque todos estamos alinhados no desejo de um ecossistema seguro e confiável. Vocês já reconheceram o problema ao exibir o aviso no GitHub.com. Agora, faria uma enorme diferença expor esse mesmo sinal através da API para que o ecossistema possa agir sobre ele.

Uma pequena melhoria da parte de vocês permitiria uma melhoria significativa em todo o ecossistema. Não é esse o melhor tipo de melhoria? 

E já que é a temporada de festas, quero compartilhar algo que tenho ouvido nos bastidores. Nas últimas semanas, conversei com alguns dos maiores atores do ecossistema, e há uma preocupação silenciosa e compartilhada de que algo possa dar errado enquanto todos tentam tirar um tempo para passar com seus entes queridos. Corrigir este problema não eliminará esse risco, é claro, mas a preocupação é real e amplamente sentida.

Boas festas, GitHub. Que tenhamos um fim de ano tranquilo.

Compartilhar:

https://www.aikido.dev/blog/the-fork-awakens-why-githubs-invisible-networks-break-package-security

Assine para receber notícias sobre ameaças.

Comece hoje, gratuitamente.

Comece Gratuitamente
Não é necessário cc

Fique seguro agora

Proteja seu código, Cloud e runtime em um único sistema centralizado.
Encontre e corrija vulnerabilidades rapidamente de forma automática.

Não é necessário cartão de crédito | Resultados da varredura em 32 segundos.