Skip to main content
Publicado por: Namastex Labs Serviços em Tecnologia Ltda — CNPJ 46.156.854/0001-62 Versão: 1.0 · 2026-04-23 Classificação: Público — distribuição livre para quem tenha instalado qualquer versão afetada Páginas relacionadas: automagik.dev/security (EN) · automagik.dev/seguranca (PT) Cópia canônica pública: automagik-dev/docs → genie/incident-response/canisterworm.mdx

Sobre este documento

Entre 21 e 22 de abril de 2026, versões maliciosas dos pacotes npm @automagik/genie e pgserve (publicados pela Namastex Labs) foram carregadas no registro público como parte da campanha CanisterWorm — um worm de supply-chain auto-propagante atribuído ao ator TeamPCP que afetou múltiplos publishers npm. Assumimos responsabilidade por este incidente. Este manual existe para ajudar qualquer pessoa ou organização que tenha instalado as versões afetadas a verificar se foi comprometida e, em caso afirmativo, remediar de forma estruturada. Se você instalou qualquer versão listada abaixo entre 2026-04-21 e 2026-04-22, leia este documento do início ao fim antes de executar qualquer comando. O caminho preferencial agora é começar com genie sec scan. Os checks manuais abaixo continuam válidos como confirmação adicional, fallback, ou triagem em hosts onde o CLI não está disponível.

1. O que aconteceu

1.1 Resumo

  • Família de malware: CanisterWorm
  • Ator atribuído: TeamPCP
  • Vetor primário: credencial GitHub OAuth de publish em ambiente Namastex foi comprometida pelo worm CanisterWorm e utilizada para publicar versões contaminadas.
  • Mecanismo: hook postinstall roda no momento da instalação do pacote, coleta credenciais locais e exfiltra para infraestrutura de comando e controle via HTTPS.
  • Propagação (worm): utiliza o token npm roubado para republicar versões contaminadas de outros pacotes em que a vítima tenha permissão de publish.

1.2 Pacotes e versões maliciosas

1.3 Versões limpas

⚠️ A distribuição via npmjs.com foi descontinuada após este incidente. Pacotes Namastex agora são shipados via Aegis — GitHub Releases assinados com cosign keyless (OIDC) + atestação SLSA L3 de proveniência. Veja §5.6 para o trust model completo e §4.3 para o caminho de install.

1.4 O que o malware coleta

Se qualquer versão maliciosa foi instalada na sua máquina, os itens abaixo foram potencialmente exfiltrados no momento da instalação:
  • Tokens npm~/.npmrc
  • Chaves SSH~/.ssh/id_* (privadas e públicas)
  • Tokens GitHub CLI / OAuth~/.config/gh/hosts.yml
  • Credenciais cloud~/.aws/, ~/.azure/, ~/.config/gcloud/
  • kubeconfig~/.kube/config, tokens de service account /var/run/secrets/kubernetes.io/
  • Arquivos .env — qualquer .env acessível no workspace
  • Histórico de shell~/.bash_history, ~/.zsh_history
  • Senhas salvas — Chrome/Chromium/Edge/Firefox
  • Carteiras crypto — MetaMask, Phantom, Exodus, Atomic (seed phrases)
  • LLM API keysANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_API_KEY em .env ou variável de ambiente
  • Variáveis de ambiente de processos em execução — via /proc/<pid>/environ
  • Credenciais Docker registry~/.docker/config.json
  • Chaves privadas TLS
⚠️ Leitura crítica: o roubo aconteceu no momento da instalação. Rotacionar chaves no GitHub não desfaz o que já foi exfiltrado — você precisa rotacionar todos os itens listados acima.
Sempre que possível, use também a saída do genie sec scan para confirmar quais tipos de material estavam presentes no host. A seção at-risk local material present on host não mostra segredos, mas lista os caminhos e artefatos locais que o malware provavelmente teria tentado ler.

2. Passo 1 — Identificar se você foi afetado

Execute todos os checks abaixo. Anote resultados antes de seguir para o Passo 2.

Usando genie sec scan (recomendado)

Rode primeiro:
Se precisar cobrir múltiplos repositórios ou serviços:
Use --json quando quiser arquivar ou automatizar a triagem:
Como interpretar:
  • LIKELY COMPROMISED — há sinais de execução, persistência, .pth, artefatos de drop, ou processo ativo. Vá direto para o Passo 3.
  • LIKELY AFFECTED — há versões comprometidas instaladas ou em cache. Trate o host como exposto e siga para o Passo 3.
  • OBSERVED ONLY — só foram encontradas referências em cache, lockfile, ou log. Ainda assim revise os checks manuais abaixo antes de declarar o host limpo.
  • NO FINDINGS — não houve evidência específica do incidente dentro do escopo escaneado.
O scanner cobre os mesmos sinais principais deste manual:
  • caches npm e bun
  • instalações locais e globais
  • históricos de shell e arquivos de inicialização
  • persistência systemd, cron, launchd, .pth
  • artefatos temporários e processos vivos
  • material local em risco para priorizar rotação
Se o scanner acusar LIKELY COMPROMISED ou LIKELY AFFECTED, continue com os passos manuais abaixo apenas para coleta complementar e preservação de evidência.

2.1 Versão instalada globalmente (bun)

2.2 Versão instalada globalmente (npm)

2.3 Cache do bun (mesmo sem instalação global, o cache basta para comprometer)

As versões maliciosas aparecem como, por exemplo:

2.4 IoCs nos arquivos do pacote

Se encontrou alguma versão suspeita no cache, confirme a presença dos arquivos maliciosos:
🚨 Se qualquer um desses arquivos existir: VOCÊ FOI INFECTADO. Vá direto para o Passo 3.

2.5 Persistência systemd

Se pgmon.service existir ou /tmp/pglog existir: há persistência ativa na máquina.

2.6 Persistência Python (.pth injection)

Legítimos em site-packages são apenas distutils-precedence.pth, _virtualenv.pth e easy-install.pth. Qualquer outro .pth é suspeito:

2.7 Conexões ativas com C2

🚨 Se aparecer qualquer resultado: a máquina está exfiltrando agora. Desconecte da rede antes de seguir.

3. Passo 2 — Interpretar o resultado


4. Passo 3 — Remediação (apenas se INFECTADO)

Execute na ordem. Não pule etapas.

4.1 Remover persistência

4.2 Purgar cache malicioso do bun

Nenhuma saída = limpo.

4.3 Remediar via Aegis

A remediação de hosts afetados é tratada pela Aegis — read-only scanner + auditable remediator, derivado de @automagik/genie sec após este incidente. Veja §5.6 para o trust model.
A Aegis purga versões comprometidas dos caches bun/npm e quarentena artefatos maliciosos (env-compat.cjs, public.pem, check-env.js). Remove persistência (pgmon.service, /tmp/pglog) e produz audit log append-only. Se algo der errado, aegis rollback <scan-id> desfaz a operação inteira via sha256-verified restore. Após a remediação, reinstale as versões limpas de @automagik/genie e pgserve seguindo o guia de install atual de cada projeto (pós-saída do npm — veja §5.6). A Aegis cuida da detecção e limpeza, não da reinstalação dos pacotes. Para ambientes não-interativos (CI, Dockerfiles), o instalador aceita -s -- --auto-install-deps. Para air-gapped, veja docs/install/ no repositório da Aegis.

4.4 Rotacionar TODAS as credenciais

🔥 Este é o passo mais importante. Qualquer credencial presente na máquina no momento da instalação foi exfiltrada. Rotacionar = revogar a existente e emitir uma nova.
Se você executou genie sec scan, use a seção at-risk local material present on host como checklist para não esquecer nenhuma classe de credencial, carteira, perfil de navegador, ou .env local presente no host comprometido. npm
GitHub CLI / PAT
Chaves SSH
💡 Lição aprendida da nossa investigação: hosts clonados a partir de um mesmo template podem compartilhar o mesmo par de chaves. Se esse for o seu caso, rotacionar em um host não basta — precisa gerar chaves únicas em cada host e atualizar authorized_keys em toda a frota.
AWS
GCP
Azure
Kubernetes
Docker registry
Arquivos .env
LLM API keys Carteiras crypto (crítico) Se MetaMask, Phantom, Exodus, Atomic ou qualquer carteira estava instalada na máquina: trate a seed phrase como comprometida. Em um dispositivo limpo:
  1. Gere uma nova seed phrase
  2. Mova todos os fundos para a nova carteira imediatamente
  3. Revogue approvals ativas (use https://revoke.cash ou equivalente)
Roubos de carteira são irreversíveis. Não existe recuperação. Chaves privadas TLS Se você hospeda serviços HTTPS com chaves no disco, rotacione os certificados e chaves privadas.

4.5 Se você tem permissão de publish no npm

O worm pode ter utilizado seu token para republicar pacotes maliciosos em seu nome. Verifique:
Se aparecerem versões inesperadas entre 2026-04-21 e 2026-04-23:
Notifique o npm Security: security@npmjs.com e, se possível, abra um Security Advisory no GitHub (GHSA).

4.6 Preservar evidências (opcional, recomendado)

Antes de destruir tudo, se tiver como, preserve:
  • Cópia dos arquivos maliciosos identificados no Passo 2 (env-compat.cjs, public.pem, check-env.js)
  • Logs de egress da máquina no período 2026-04-21 a 2026-04-22
  • Saída de ss -tnp, journalctl --user -u pgmon, last, who
Isso ajuda análise forense e atribuição.

5. Passo 4 — Prevenção (todos os usuários, infectados ou não)

5.1 Pinar versões no package.json

Nunca use latest para pacotes de supply-chain sensível. Use versões explícitas:

5.2 Desabilitar postinstall em CI/CD

Para desenvolvimento local onde scripts são necessários, avalie ferramentas como @lavamoat/allow-scripts para controle granular.

5.3 Revisar mecanismos de auto-update

Muitas ferramentas têm auto-update (genie-update-check.sh, cron jobs, tmux status hooks etc.). Auto-update foi o vetor primário de infecção em larga escala — a máquina instalou sozinha sem ação do usuário. Verifique:
Se encontrar: pinar na versão limpa conhecida antes de reabilitar.

5.4 Exigir 2FA + provenance

  • Habilite 2FA em toda conta npm e GitHub.
  • Use npm publish --provenance (GitHub Actions com OIDC).
  • Para repositórios críticos, exija assinatura de commits (GPG/Sigstore) e revisão obrigatória antes de merge.

5.5 Segregar credenciais de produção

Credenciais de produção nunca devem estar em máquinas de desenvolvimento. Use workstations dedicadas, bastions, ou cofres temporários (HashiCorp Vault, Doppler, AWS Secrets Manager com sessões efêmeras).

5.6 Como a Namastex se defende hoje

A resposta a este incidente levou a três mudanças estruturais na nossa postura de segurança. Documentamos aqui porque outras equipes podem querer adotar o mesmo padrão. Trust-level — saída da rede pública npm. O vetor primário deste incidente foi o próprio npmjs.com: tokens de publish com escopo amplo, sem verificação de identidade do publisher no install-time, propagação self-spread via dependências. Concluímos que registries com publish-by-token não são uma base de trust segura para shipping de software crítico. Por isso, os pacotes @automagik/genie e pgserve foram movidos para distribuição própria. Agora usamos GitHub Releases assinados, sem dependência do registro npm para o caminho default de install. Distribution-level — Aegis (automagik-dev/aegis). Novo módulo do bundle Automagik, derivado de @automagik/genie sec, dedicado a shipping seguro de AI. Cada release é assinada com cosign keyless (OIDC via GitHub Actions) e atestada com SLSA L3 provenance. O instalador (curl -fsSL .../install.sh | bash) verifica assinatura e proveniência antes de tocar qualquer arquivo. ~/.npmrc do usuário nunca é tocado. Verificação em runtime via aegis verify-install. Host-level — aegis scan. Scanner read-only que roda em workspaces de desenvolvimento e em CI antes de operações sensíveis. Detecta versões comprometidas instaladas/cacheadas, payloads conhecidos, persistência (pgmon.service, .pth), conexões a C2 conhecido, e enumera material local em risco. Roda como gate contínuo, não só em resposta a incidente. Aegis evolui em ciclos curtos. Phase 2 (@automagik/aegis-signatures) traz definições de incidentes adicionais via package separado com release cadence independente — operadores rodam aegis signatures update em cron, novas worm definitions chegam em minutos. Detalhes técnicos completos: github.com/automagik-dev/aegis.

6. Referência rápida — Indicadores de Comprometimento (IoCs)

Arquivos maliciosos

Infraestrutura C2 (bloquear no perímetro)

Persistência

Firewall — exemplo (iptables)

Em Sophos, OPNsense, pfSense ou similares, crie um grupo CanisterWorm-C2 com os IPs/hosts acima e uma regra de bloqueio em posição topo, com logging habilitado.

7. Checklist de um olhar (imprima e cole no monitor)

  • Verifiquei cache bun e npm — nenhuma versão da tabela 1.2 presente
  • Rodei genie sec scan --all-homes --root <repo> e revisei o veredicto
  • Revisei at-risk local material present on host para priorizar rotação
  • Verifiquei env-compat.cjs, public.pem, check-env.js — ausentes
  • Verifiquei pgmon.service e /tmp/pglog — ausentes
  • Verifiquei .pth Python — apenas legítimos
  • Verifiquei conexão ativa C2 — nenhuma
  • Se infectado: rotacionei npm, GitHub, SSH, AWS, GCP, Azure, kubeconfig, Docker
  • Se infectado: rotacionei todas as LLM keys e revoguei sessões ativas
  • Se infectado: tratei seed phrases crypto como comprometidas
  • Pinnei versões limpas no package.json
  • Desabilitei auto-update até validar a fonte
  • Bloqueei IoCs no meu perímetro

8. Contato e reporte

SLA de resposta: 2 horas em horário comercial (UTC-3). Se você foi afetado pelo incidente e precisa de ajuda para executar remediação, escreva para privacidade@namastex.ai. Apoiamos com orientação sem custo, dentro do razoável. Reportes privados de segurança relacionados a qualquer pacote Namastex: privacidade@namastex.ai (PGP disponível sob solicitação).

9. Referências externas


10. Histórico de revisões


11. Operator playbook (English) — three-branch decision tree

The preceding sections are the public advisory for any operator or organization that installed a compromised version. The following section is the cold-runnable operator playbook tied to genie sec scan status bands. Use it when you already have @automagik/genie on the host and you need a step-by-step remediation recipe that matches exactly what the CLI is about to ask of you.

11.1 When to use this playbook

Use this playbook when any of the following is true:
  • genie sec scan returned LIKELY COMPROMISED, LIKELY AFFECTED, or OBSERVED ONLY.
  • A host ran @automagik/genie versions 4.260421.33 through 4.260421.40, or pgserve 1.1.111.1.14, between 2026-04-21 and 2026-04-22.
  • An unexpected pgmon.service, /tmp/pglog, or suspicious .pth file appeared on disk.
  • Egress to telemetry.api-monitor.com, 143.198.237.25, or any *.raw.icp0.io was logged.

11.2 Scanner output → decision tree

genie sec scan emits a status band at the top of its report. That band picks the branch below.
Non-negotiable first step for any branch: verify the CLI you are about to trust is genuine. Run genie sec verify-install before any remediate, restore, or rollback invocation. If that call cannot return exit 0, read §11.7 Escalation — --unsafe-unverified before touching the host.

11.3 LIKELY COMPROMISED — full remediation

Preconditions: genie sec scan returned LIKELY COMPROMISED. A live process, persistence unit, or dropped payload was detected. Assume the host is exfiltrating or about to exfiltrate.

Step 1 of 7 — Snapshot live processes (evidence preservation)

Before any kill action, capture the live state of every PID the scanner flagged. This output is the forensic baseline for the post-mortem.

Step 2 of 7 — Block egress to known C2 hosts

CanisterWorm exfiltrates over HTTPS to telemetry.api-monitor.com, 143.198.237.25, and multiple *.raw.icp0.io ICP canisters. Block at the host level before scanning. Linux — iptables
macOS — pf
Windows — netsh advfirewall

Step 3 of 7 — Verify the CLI and run an authoritative scan

genie sec verify-install must return exit 0 before you trust the binary. If it does not, see §11.7.
Capture the scan_id from the output — every subsequent step references it.

Step 4 of 7 — Generate a remediation plan, review, apply

genie sec remediate is dry-run by default. Generate the plan, read it, then apply.
If --apply aborts partway through, resume with:
If --apply completed but broke something, see §11.6 Escalation — rollback.

Step 5 of 7 — Rotate credentials in priority order

Any credential the host could read at install time was exfiltrated. Rotation = revoke the old, issue the new. Order matters. genie sec remediate --apply emits a per-host rotation checklist at the end of its run; the table above is the fleet-level order across hosts.

Step 6 of 7 — Rebuild image or restore from pre-compromise snapshot

If no clean snapshot exists: re-provision the host from a fresh image, install @automagik/genie from the current stable line, run genie sec verify-install, and restore workload state from your backup channel (not from the compromised host).

Step 7 of 7 — Write the post-mortem

Use the template in §11.8 Post-mortem template. Paste the scan_id from Step 3; the audit log under $GENIE_SEC_AUDIT_LOG contains the full action trail keyed off that id.

11.4 LIKELY AFFECTED — purge → rescan → rotate

Preconditions: genie sec scan returned LIKELY AFFECTED. Malicious versions were installed or cached. Postinstall execution cannot be ruled out, but no live process, persistence unit, or dropped payload was observed.

Step 1 of 4 — Purge caches and installed packages

Step 2 of 4 — Re-scan, confirm delta is empty

Step 3 of 4 — Install clean versions

Step 4 of 4 — Rotate credentials that were live during the compromise window

Rotate every credential that was in environment or on disk between 2026-04-21 and 2026-04-22. If you cannot bound the window, rotate everything in the §11.3 Step 5 table.

11.5 OBSERVED ONLY — clear → rescan

Preconditions: genie sec scan returned OBSERVED ONLY. Only passive references (cache index without unpacked contents, lockfile entries, shell history) were found. No dropped payload, no persistence, no live process.

Step 1 of 3 — Clear the referenced cache / history entries

Step 2 of 3 — Re-scan to confirm

Step 3 of 3 — Do not rotate credentials yet

OBSERVED ONLY means we have no evidence the postinstall script executed. Skip credential rotation unless later evidence (shell history showing an install + invoke, auditd execve of node scripts/env-compat.cjs, egress logs to a C2 host) surfaces. If any of those appears, re-classify as LIKELY AFFECTED and run §11.4.

11.6 Escalation — rollback

Use genie sec rollback <scan_id> when genie sec remediate --apply completed but broke something on the host. Rollback walks the audit log in reverse, restoring every quarantined item to its original path with sha256-verified content. When to reach for this: a service fails to start after remediation, a legitimate config file was quarantined, a dependency your application needs is gone. Rollback is safe — it only touches items the audit log recorded.

11.7 Escalation — --unsafe-unverified

genie sec remediate --apply refuses to run unless genie sec verify-install returned exit 0. The --unsafe-unverified <INCIDENT_ID> flag is the only documented escape hatch. Every invocation is written to $GENIE_SEC_AUDIT_LOG with the incident id, the typed ack, and the reason.

When --unsafe-unverified is legitimate

There are three contexts in which --unsafe-unverified is a correct operator choice. Context 1 — Burned public key / burned signing identity A Namastex security officer confirmed the cosign keyless identity is compromised (see docs/security/key-rotation.md). verify-install returns exit 3 (signer-identity-mismatch). The host needs remediation now; rotation will take hours.
Audit-log verification:
Context 2 — CI pre-signing period The release channel is older than the genie-supply-chain-signing cutover and does not ship a signed tarball. verify-install returns exit 5 (no signature material found). Common during staged rollouts between 4.260423.x and 4.260424.x.
Context 3 — Integration test harness scripts/test-runbook.sh and the CI workflow exercise remediate --apply against a fixture on an unsigned development tarball. The INCIDENT_ID is a fixed sentinel recognized by the harness.

When --unsafe-unverified is NOT legitimate

  • “It’s faster.” The prompt is the point; verification is the contract.
  • “The prompt is annoying.” See above.
  • “I don’t have the key locally.” There is no key — the signing identity is a three-value tuple (see SECURITY.md § Release Signing). If verify-install exits 5, use Context 2.
  • “Our release channel is old.” Upgrade. If that is not possible right now, use Context 2 with the correct release-line identifier.
Any --unsafe-unverified invocation whose incident id does not map to one of the three legitimate contexts is treated as an incident of its own by post-hoc review.

11.8 Post-mortem template

Copy the block below into your incident channel and fill in every field. The scan_id ties it to the persisted scan JSON, the audit log, and the remediation plan manifest.

Documento mantido por Cezar Vasconcelos — DPO e CTO, Namastex Labs Serviços em Tecnologia Ltda. Distribuição livre. Redistribuição encorajada. Atribuição apreciada.