A maioria dos grandes ataques à cadeia de fornecimento dos últimos dois anos funcionou da mesma forma. Um programador executou npm install e uma dependência que nunca escolheu correu código na sua máquina antes de ele escrever uma única linha. O npm permite isto por design e está agora a recuar nessa decisão. O Go nunca o permitiu. Este artigo analisa quanto é que essa única diferença explica, onde o Go é realmente mais seguro e onde enfrenta os mesmos riscos que o Node. Cada afirmação tem uma fonte.
Resumo rápido
Go vs Node.js: segurança da cadeia de fornecimento em resumo
| Aspeto | Go (Golang) | Node.js (npm) |
|---|---|---|
| Execução de código na instalação | Nenhuma. go get/go build não executam scripts de pacotes. | preinstall/install/postinstall executam código arbitrário automaticamente. |
| Quando corre o código malicioso | Só quando é importado e a função é chamada. | No momento em que instalas, antes de escreveres uma linha. |
| Garantia de integridade | Registo de transparência de checksums em árvore de Merkle (sum.golang.org), com qualquer adulteração visível para sempre. | Hashes no lockfile e, mais recentemente, proveniência. Historicamente mais fraca. |
| Resolução de versões | Minimal Version Selection (seleção da versão mínima). As atualizações são explícitas. | Intervalos semver (^, ~). Um novo patch malicioso pode ser resolvido automaticamente. |
| Superfície de dependências | Biblioteca padrão grande, menos dependências diretas. | Cultura de módulos minúsculos, árvores transitivas enormes. |
| Análise de vulnerabilidades | O govulncheck faz análise de alcançabilidade, por isso há menos falsos alarmes. | O npm audit sinaliza a árvore inteira, o que leva à fadiga de alertas. |
| Modelo de registo | Descentralizado. Os módulos são URLs de código-fonte. | Contas centrais. Um único phishing expõe um portefólio inteiro. |
| Continua exposto a | Mantenedores vítimas de phishing, typosquats, malware guardado na cache do proxy. | Tudo isso, mais worms baseados em scripts de instalação. |
O Go fica à frente no comportamento por omissão e na superfície de ataque. Um atacante determinado que engane com phishing um mantenedor humano consegue passar em qualquer um dos ecossistemas.
Porque é que o Go evita o ataque que mais afeta o npm?
O Go não tem scripts de instalação. Quando executas npm install, cada pacote da árvore transitiva pode registar hooks de ciclo de vida (preinstall, install, postinstall). O npm executa-os automaticamente, com os privilégios do teu utilizador, antes de teres executado ou sequer lido uma única linha (documentação de scripts do npm). O GitHub classificou os scripts de instalação como a maior superfície de execução de código do ecossistema npm (GitHub Security, 2025).
O Go deixou isto de fora de propósito. Não tem hooks de compilação. O go get descarrega e verifica o código-fonte, o go build compila-o e nenhum deles executa scripts definidos pelo pacote. Uma dependência Go envenenada fica ali como simples código-fonte até que o teu código a importe e chame a função maliciosa. Essa janela é muito mais estreita e mais fácil de detetar do que código que corre para toda a gente em cada instalação.
Eis o que cada comando faz:
example.bashbash# npm: the postinstall hook runs on every install, automatically $ npm install left-pad > [email protected] postinstall > node ./scripts/setup.js # <- arbitrary code, your privileges, right now # go: nothing in the package gets to run during fetch or build $ go get example.com/some/module go: downloaded example.com/some/module v1.0.0 # source fetched, checksum verified, nothing executed
É por causa desta diferença que o npm v12, lançado em julho de 2026, bloqueia os scripts de instalação por omissão, e que o pnpm já fez o mesmo na v10 (documentação de scripts do npm). As ferramentas de JavaScript estão a aproximar-se do comportamento que o Go tinha desde o lançamento.
Qual é a dimensão do problema da cadeia de fornecimento do npm, em números?
O npm é, de longe, o maior alvo. A Sonatype identificou 454.648 novos pacotes maliciosos em 2025, o que elevou o seu total acumulado de pacotes bloqueados para mais de 1,23 milhões, um salto de 75 % face ao ano anterior. Mais de 99 % desse malware de código aberto estava no npm (Sonatype, 11.º State of the Software Supply Chain, 2026). O seu índice de malware do quarto trimestre de 2025 situou o valor em 99,8 % do malware bloqueado nesse trimestre.
Não existe sequer uma contagem publicada de módulos Go maliciosos. A Sonatype, a OpenSSF e a maioria dos fornecedores não acompanham o Go como ecossistema separado nos seus índices de malware, porque há demasiado poucos incidentes para indexar. Essa lacuna nos dados já diz muito.
Onde estava o malware de código aberto em 2025 (percentagem de novos pacotes maliciosos, por ecossistema):
| Ecossistema | Percentagem do malware de código aberto de 2025 |
|---|---|
| npm | Mais de 99 % |
| Todos os outros (incl. Go)* | Menos de 1 % |
*Foram identificados 454.648 novos pacotes maliciosos em 2025. O Go não é acompanhado como ecossistema separado, porque há demasiado poucos incidentes para indexar. Fonte: Sonatype, 11.º State of the Software Supply Chain, 2026.
O que aconteceu de facto na vaga de worms do npm de 2025 e 2026?
Uma série de worms autopropagáveis transformou um risco conhecido numa emergência constante, e todos eles usaram scripts de instalação. O npm tem incidentes mediáticos há anos. Em 2018, o event-stream escondeu um ladrão de carteiras de Bitcoin numa dependência descarregada cerca de 8 milhões de vezes. Em 2021, o ua-parser-js distribuiu mineradores de criptomoedas após o roubo de uma conta. Mas foi em 2025 que os incidentes começaram a surgir uns atrás dos outros.
| Data | Incidente | O que aconteceu |
|---|---|---|
| 8 set. 2025 | qix vítima de phishing | 18 pacotes sequestrados, incluindo chalk e debug. Cerca de 2,6 mil milhões de downloads semanais expostos. |
| set. 2025 | Shai-Hulud | Primeiro worm do npm. Um hook postinstall recolhia credenciais e injetava-se em cerca de 100 pacotes adicionais por vítima. |
| 24 nov. 2025 | Shai-Hulud 2.0 | Passou para preinstall e acrescentou a eliminação do diretório pessoal. Cerca de 796 pacotes, encontrados em 27 % dos ambientes cloud analisados. |
| 31 mar. 2026 | axios | Atores norte-coreanos manipularam o mantenedor com engenharia social. Um RAT em postinstall desencadeou contactos com servidores C2 em mais de 12.000 projetos. |
| jun. 2026 | Miasma | Contornou o bloqueio de scripts de instalação do npm com a técnica «Phantom Gyp», uma recompilação implícita do node-gyp. |
O comprometimento do qix em setembro de 2025 começou com um email convincente de reposição da 2FA, enviado a partir do domínio falsificado npmjs.help. O atacante apoderou-se da conta do mantenedor Josh Junon e publicou versões maliciosas de 18 pacotes. Entre eles estavam chalk (~300 milhões de downloads por semana) e debug (~358 milhões), para uma exposição combinada acima de 2,6 mil milhões de downloads semanais. A carga maliciosa era um crypto-clipper que atuava no navegador, e esteve ativa durante cerca de duas horas.
Dias depois chegou o Shai-Hulud, o primeiro verdadeiro worm do npm. Na instalação, o seu bundle.js recolhia credenciais de npm, GitHub, AWS e GCP e executava o TruffleHog para extrair segredos. Depois usava os tokens do npm roubados para se injetar em até cerca de 100 pacotes adicionais de cada vítima. A CISA emitiu um alerta (CISA, 2025). A Sonatype atribui 171.740 pacotes maliciosos a campanhas autorreplicantes do npm ao longo de poucos meses.
O Shai-Hulud 2.0 (24 de novembro de 2025) passou a execução para preinstall para chegar a mais máquinas. Instalou o runtime Bun para contornar a monitorização baseada em Node e acrescentou um mecanismo de recurso destrutivo capaz de apagar um diretório pessoal. A Wiz encontrou pacotes afetados em cerca de 27 % dos ambientes cloud que analisou (Wiz, 2025).
Em 2026 ficou claro que bloquear os scripts de instalação não bastaria por si só. O comprometimento do axios (31 de março de 2026) não começou com uma palavra-passe roubada por phishing. Atores ligados à Coreia do Norte (identificados como UNC1069 / Sapphire Sleet) visaram o mantenedor principal com uma empresa falsa, um espaço de trabalho do Slack com marca própria e uma chamada no Teams que instalou um RAT na máquina do mantenedor. Depois publicaram versões maliciosas do axios (mais de 100 milhões de downloads semanais) com um RAT em postinstall. A StepSecurity detetou contactos anómalos com servidores C2 em mais de 12.000 projetos (StepSecurity, 2026). Depois, o Miasma (junho de 2026) contornou o bloqueio de scripts de instalação que o npm estava prestes a introduzir, com a técnica «Phantom Gyp». O pacote inclui um ficheiro binding.gyp, e a recompilação implícita do node-gyp feita pelo npm executa a carga maliciosa sem qualquer script declarado.
Então o Go é uma solução mágica? Não exatamente
As predefinições do Go travam toda uma classe de ataques, mas mesmo assim houve atacantes a visar o Go algumas vezes. Os módulos Go maliciosos documentados em 2025 contam-se em poucas dezenas, espalhados por um punhado de campanhas. Ao lado das centenas de milhares do npm, é um número ínfimo. O caso mais notável merece ser explicado, porque mostra quanto trabalho um atacante tem para contornar o design do Go.
O backdoor boltdb-go/bolt foi divulgado em fevereiro de 2025, mas plantado já em novembro de 2021. Fazia typosquatting do popular módulo BoltDB (github.com/boltdb/bolt), do qual dependem milhares de pacotes e que era usado na Shopify e na Heroku, e trazia um backdoor de comando e controlo. O atacante publicou a v1.3.1 maliciosa, deixou que o Go Module Mirror a guardasse em cache e depois reescreveu a tag de Git para apontar de novo para código limpo. Quem auditasse o repositório no GitHub via código limpo, enquanto o proxy continuava a servir o backdoor. Funcionou, mas só explorando um caso-limite do sistema de cache. No npm, um hook de instalação teria feito o mesmo sem esse esforço (Socket, 2025).
Surgiram mais algumas campanhas em 2025. Em março houve uma vaga de typosquats de hypert e layout com malware do tipo loader dirigido a programadores do setor financeiro. Houve também alguns módulos que apagavam discos e um ladrão de credenciais SSH. Todas estas campanhas foram isoladas, e cada uma precisava que um programador escrevesse o caminho de importação errado. Nenhuma correu automaticamente.
Quando um módulo malicioso é reportado, a equipa de segurança do Go remove-o do proxy, que passa a devolver um 403 SECURITY ERROR, e adiciona-o à base de dados de vulnerabilidades do Go. No caso do boltdb-go, a Google removeu o módulo do proxy e do GitHub e registou-o na base de dados de vulnerabilidades. Também apontou para o trabalho em curso na análise de capacidades com o Capslock e em comparações com o deps.dev. As defesas do Go tornam os ataques muito mais caros, mas não garantem segurança, e as de nenhum outro ecossistema a garantem.
O que torna o Go estruturalmente mais seguro?
Além de não ter scripts de instalação, o Go toma outras quatro decisões de design que aumentam a vantagem.
A base de dados de checksums do Go é invulgarmente robusta. O teu go.sum guarda os hashes SHA-256 de todas as dependências. O sum.golang.org é um registo de transparência em árvore de Merkle, ao estilo do Certificate Transparency. Anota o hash de cada versão de um módulo na primeira vez que alguém a descarrega e guarda-o para sempre (referência de módulos do Go). O comando go verifica as provas de inclusão e de consistência antes de confiar em qualquer código, por isso uma tag de Git reescrita com force push ou um proxy adulterado falham de forma visível. O criptógrafo Filippo Valsorda, que liderou a equipa de segurança do Go na Google, defende que o Go tem o melhor modelo de integridade de pacotes de qualquer ecossistema de linguagem, porque todos os clientes do mundo resolvem uma dada versão de um módulo para os mesmos bytes, para sempre (Filippo Valsorda). O registo tem um limite. Prova consistência, não que o código seja bom, e só ajuda se alguém o monitorizar.
A Minimal Version Selection atrasa as versões más. As compilações do Go usam a versão mais baixa que satisfaz todos os requisitos, e as atualizações são explícitas (referência da MVS). Com os intervalos ^ e ~ do npm, um patch malicioso acabado de publicar pode acabar automaticamente numa compilação. Em Go, uma nova versão maliciosa não se espalha aos projetos que dependem dela até que uma pessoa suba deliberadamente a versão exigida. Os worms qix e Shai-Hulud dependiam exatamente da atualização automática que a MVS não faz.
O govulncheck usa análise de alcançabilidade para reduzir os falsos alarmes. O scanner oficial do Go consulta a base de dados de vulnerabilidades curada em vuln.go.dev e só avisa quando o teu código chama de facto o símbolo vulnerável (govulncheck, blog do Go). O npm audit sinaliza todas as versões vulneráveis em qualquer ponto da árvore, quer chegues a usá-las quer não, e os programadores aprendem a ignorá-lo.
Não há uma conta central cuja tomada exponha um portefólio inteiro. Os módulos Go são identificados pelo URL do código-fonte, por isso dependem da segurança da conta do GitHub (ou do GitLab). No npm, uma única conta tomada expõe tudo o que esse mantenedor possui. Essa diferença explica em parte porque é que os worms do npm se espalham como se espalham, enquanto os incidentes em Go ficam contidos.
A biblioteca padrão maior também ajuda. HTTP, JSON, criptografia e templates vêm todos com o Go, por isso um projeto típico tem menos dependências diretas e menos mantenedores em quem tem de confiar. Um estudo de 2025 concluiu, ainda assim, que a amplificação por dependência do Go (cerca de 4,48x) é próxima da do npm (cerca de 4,32x), por isso cada pacote Go não traz menos dependências transitivas do que um pacote npm. O Go fica à frente porque os projetos começam com menos dependências diretas, o que mantém mais pequeno o grupo de pessoas em quem confias.
O que as predefinições do Go não cobrem
O Go fecha automaticamente as portas maiores. Os riscos abaixo aplicam-se a todos os ecossistemas, incluindo o Go, por isso tens de os cobrir tu próprio.
- Um mantenedor vítima de phishing consegue passar as defesas de qualquer ecossistema. Se a conta de GitHub de um mantenedor for tomada, o atacante pode criar a tag de uma versão maliciosa, e a base de dados de checksums regista-a fielmente porque não consegue distinguir código bom de código mau. Um ataque ao estilo do axios funciona contra todos os ecossistemas, e é por isso que a indústria está a adotar chaves de hardware e trusted publishing (publicação de confiança).
- Continuas a escolher as dependências pelo nome. A verificação de checksums do Go impede a adulteração de um módulo que escolheste, mas não te impede de escolher um typosquat. Confirma o caminho de importação contra o repositório canónico antes de adicionares uma dependência.
- A imutabilidade do proxy é, sobretudo, uma vantagem. A cache que garante que todas as compilações obtêm bytes idênticos foi também o que manteve acessível o backdoor do boltdb-go depois de a tag de Git ter sido limpa. Esse caso foi raro, e o processo de remoção da equipa do Go e a base de dados de vulnerabilidades cobrem-no.
- As predefinições protegem a instalação, não a execução. A vantagem do Go é que nada corre durante o download ou a compilação. Assim que importas e chamas uma dependência, ela corre com os teus privilégios, tal como em qualquer linguagem. Isolar código não confiável em tempo de execução é um problema à parte, em qualquer ecossistema.
- Mantém a proteção ativa. O único erro autoinfligido é definir
GOSUMDB=offde forma generalizada, o que desliga a verificação de checksums descrita acima. Deixa-a ligada e limita oGOPRIVATEapenas a caminhos genuinamente internos.
Como é que os dois ecossistemas estão a convergir para as mesmas soluções?
Os dois ecossistemas estão a adotar as mesmas defesas, porque em ambos o ponto fraco são as pessoas. Depois da vaga de 2025, o GitHub anunciou 2FA obrigatória com FIDO/WebAuthn, tokens granulares de curta duração e a descontinuação dos tokens clássicos legados. Também está a promover o trusted publishing via OIDC, com proveniência criptográfica das compilações (GitHub Security, 2025). O npm v12 (julho de 2026) bloqueia os scripts de instalação por omissão e acrescenta um período de espera min-release-age, para que um pacote que só esteve publicado duas horas nunca chegue até ti.
Estas mudanças ajudam. Mas o axios mostrou onde deixam de funcionar. Nenhuma política de tokens trava um mantenedor cujo portátil está a correr um RAT. Só chaves de hardware FIDO2, combinadas com instalações com proveniência verificada e período de espera, o teriam travado. As duas comunidades estão a aprender que os atacantes visam mais o mantenedor do que as ferramentas. O Go continua a ter aí uma vantagem. Mesmo quando um mantenedor é comprometido, os danos são menores, porque nada corre na instalação.
O que deves fazer já?
Os passos dependem da tua stack.
Se escreves Go:
- Nunca definas
GOSUMDB=offnemGONOSUMCHECKde forma generalizada. Limita oGOPRIVATEestritamente a caminhos genuinamente internos. - Faz commit do
go.sume compila com-mod=readonly. - Executa
govulncheck ./...no CI como barreira que tem em conta a alcançabilidade. - Verifica se as novas dependências são typosquats. Confirma os caminhos de importação contra o repositório canónico antes de as adicionares.
- Monitoriza as novas versões das dependências críticas com o Socket ou o deps.dev.
Se escreves Node:
- Atualiza para o npm 11.16.0+ e define
ignore-scripts=true, com uma lista de permissões (como@lavamoat/allow-scripts) para os poucos pacotes que precisam mesmo de scripts. - Usa
npm cicom um lockfile congelado, fixa versões exatas e define um período de esperamin-release-agede 3 a 7 dias, para que comprometimentos de duas horas nunca cheguem até ti. - Adota o trusted publishing (OIDC) e chaves de hardware FIDO2. Não confies no TOTP para publicar.
- Usa uma verdadeira análise de composição de software (Socket, Snyk) com deteção comportamental, e não apenas o
npm audit. - Regista publicamente, por precaução, os nomes dos teus pacotes internos para bloquear a confusão de dependências.
Perguntas frequentes
O Go é mesmo mais seguro do que o Node.js na cadeia de fornecimento?
Sim, estruturalmente. A razão principal é que o go get e o go build não executam scripts no momento da instalação, o que elimina o vetor preinstall/postinstall por trás de quase todos os grandes worms do npm de 2025 e 2026. Mais de 99 % do malware de código aberto de 2025 apareceu no npm (Sonatype, 2026). O Go é mais seguro, mas não é imune.
Qual é a maior diferença de segurança entre o Go e o npm?
A execução de código no momento da instalação. No npm install, o npm executa automaticamente scripts arbitrários dos pacotes, com os teus privilégios, para cada pacote da árvore. O Go não tem qualquer hook de compilação, por isso uma dependência maliciosa não faz nada até o teu código a importar e a chamar. É por isso que o npm v12 bloqueia agora os scripts de instalação por omissão, que é como o Go sempre se comportou.
O Go já sofreu algum ataque à cadeia de fornecimento?
Sim. O backdoor boltdb-go fez typosquatting do BoltDB e serviu um backdoor de acesso remoto a partir da cache de módulos do Go durante três anos (Socket, 2025). Uma campanha de 2025 com hypert/layout distribuiu pelo menos sete typosquats com malware do tipo loader. Estes incidentes são reais mas raros, e os módulos maliciosos são removidos do proxy assim que são reportados.
O que é a base de dados de checksums do Go e porque é que importa?
O sum.golang.org é um registo de transparência em árvore de Merkle. Guarda de forma permanente o hash de cada versão de um módulo na primeira vez que essa versão é vista. O comando go verifica estas provas antes de confiar no código, por isso uma adulteração ou uma tag de Git reescrita falham de forma visível (referência de módulos do Go). Todos os clientes obtêm bytes idênticos para uma dada versão, e essa é a garantia de integridade mais forte na gestão de pacotes de uso corrente.
Bloquear os scripts de instalação do npm resolve o problema?
Ajuda muito, mas não resolve tudo. O ataque ao axios usou um RAT em postinstall depois de manipular o mantenedor com engenharia social, e a campanha Miasma contornou o bloqueio de scripts através de uma recompilação implícita do node-gyp. Bloquear scripts, juntamente com chaves de hardware FIDO2, um período de espera após cada publicação e verificação de proveniência, fecha a maior parte da lacuna. Um mantenedor vítima de phishing continua a conseguir passar qualquer controlo isolado.
Devo trocar o Node pelo Go só por causa da segurança?
A segurança conta a favor do Go, mas a maioria das equipas escolhe uma linguagem por tudo o que ela traz: concorrência, recrutamento, ecossistema e a rapidez com que conseguem entregar. O Go é uma linguagem de backend sólida e também a mais segura, pela sua estrutura, contra ataques à cadeia de fornecimento. Se já estás a considerá-lo, as predefinições mais seguras são mais uma razão para o aprenderes.
Fontes
Fontes primárias citadas neste artigo (última verificação a 29 de junho de 2026):
- Sonatype: State of the Software Supply Chain
- Socket: Malicious Go module exploits proxy caching for persistence (boltdb-go)
- GitHub Security: Our plan for a more secure npm supply chain
- Referência de módulos do Go: base de dados de checksums
- Referência de módulos do Go: Minimal Version Selection
- Blog do Go: govulncheck
- Go: gestão de vulnerabilidades no Go
- Documentação do npm: scripts e hooks de ciclo de vida
- Alex Birsan: Dependency Confusion
- CISA: avisos de cibersegurança
- Wiz: blog de investigação
- StepSecurity: blog
- Filippo Valsorda: words.filippo.io
