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
postinstallroda 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
| Pacote | Versões comprometidas | Status no npm |
|---|---|---|
@automagik/genie | 4.260421.33 até 4.260421.40 | Depreciadas e removidas |
pgserve | 1.1.11, 1.1.12, 1.1.13, 1.1.14 | Depreciadas e removidas |
1.3 Versões limpas
| Pacote | Versão segura |
|---|---|
@automagik/genie | 4.260422.4 ou posterior |
pgserve | 1.1.10 |
⚠️ 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.envacessí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 keys —
ANTHROPIC_API_KEY,OPENAI_API_KEY,GOOGLE_API_KEYem.envou 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:
--json quando quiser arquivar ou automatizar a triagem:
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.
- 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
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)
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
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 apenasdistutils-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
| Situação | Veredicto | Ação |
|---|---|---|
genie sec scan retorna LIKELY COMPROMISED | INFECTADO | Desconecte da rede se possível e execute o Passo 3 completo |
genie sec scan retorna LIKELY AFFECTED | INFECTADO | Execute o Passo 3 completo |
genie sec scan retorna OBSERVED ONLY | OBSERVADO | Continue nos checks manuais; se houver dúvida operacional, trate como infectado |
genie sec scan retorna NO FINDINGS | CLEAN provisório | Se o escopo cobriu todos os homes e roots relevantes, siga para o Passo 4 |
| Nenhuma versão maliciosa no cache, nenhum IoC | CLEAN | Vá direto para o Passo 4 (prevenção) |
Versão maliciosa no cache, mas env-compat.cjs/check-env.js ausentes | OBSERVADO | Cache presente mas postinstall pode não ter rodado — trate como INFECTADO por precaução (Passo 3) |
env-compat.cjs, public.pem ou check-env.js presentes | INFECTADO | Execute o Passo 3 completo |
pgmon.service ativo ou conexão C2 detectada | INFECTADO ATIVO | Desconecte a rede imediatamente, depois Passo 3 |
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
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.
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
💡 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
.env
- Anthropic: https://console.anthropic.com → API Keys → revogar e emitir nova
- OpenAI: https://platform.openai.com/api-keys → revogar e emitir nova
- Google: https://aistudio.google.com/apikey → revogar e emitir nova
- Verifique o faturamento das últimas 72h para identificar uso anômalo.
- Gere uma nova seed phrase
- Mova todos os fundos para a nova carteira imediatamente
- Revogue approvals ativas (use https://revoke.cash ou equivalente)
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: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
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
@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:
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óprionpmjs.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)
| Indicador | Tipo | Observação |
|---|---|---|
telemetry.api-monitor.com | Webhook de exfiltração | Principal endpoint de coleta |
143.198.237.25 | IP | Resolução atual do webhook |
cjn37-uyaaa-aaaac-qgnva-cai.raw.icp0.io | ICP canister | C2 secundário |
tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0.io | ICP canister | C2 secundário |
Persistência
| Indicador | Tipo |
|---|---|
~/.config/systemd/user/pgmon.service | Serviço systemd |
/tmp/pglog, /tmp/pg_log | Binários auxiliares |
.pth suspeito em site-packages Python | Persistência TeamPCP |
Firewall — exemplo (iptables)
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 hostpara priorizar rotação - Verifiquei
env-compat.cjs,public.pem,check-env.js— ausentes - Verifiquei
pgmon.servicee/tmp/pglog— ausentes - Verifiquei
.pthPython — 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
| Canal | Para quê | |
|---|---|---|
| DPO Namastex (Cezar Vasconcelos) | dpo@namastex.ai | Questões de privacidade e LGPD |
| Canal de segurança e incidentes | privacidade@namastex.ai | Relatar impacto, pedir ajuda, compartilhar IoCs |
| Canal direto CTO | cezar@namastex.ai | Questões técnicas críticas |
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
- Socket.dev — Namastex npm packages compromised: CanisterWorm
- BleepingComputer — New npm supply-chain attack self-spreads
- Endor Labs — CanisterWorm analysis
- Kodem Security — Compromised npm publisher
- CSO Online — Malicious pgserve/automagik developer tools
- The Register — Another npm supply-chain attack
10. Histórico de revisões
| Data | Versão | Mudança |
|---|---|---|
| 2026-04-23 | 1.0 | Publicação inicial consolidada pós-investigação |
| 2026-04-24 | 1.1 | Adicionado operator playbook em inglês (§11) com árvore de decisão de três ramos, escalations e template de post-mortem |
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 togenie 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 scanreturnedLIKELY COMPROMISED,LIKELY AFFECTED, orOBSERVED ONLY.- A host ran
@automagik/genieversions4.260421.33through4.260421.40, orpgserve1.1.11–1.1.14, between 2026-04-21 and 2026-04-22. - An unexpected
pgmon.service,/tmp/pglog, or suspicious.pthfile appeared on disk. - Egress to
telemetry.api-monitor.com,143.198.237.25, or any*.raw.icp0.iowas 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.
| Scanner status | Branch | Severity |
|---|---|---|
LIKELY COMPROMISED | §11.3 LIKELY COMPROMISED | Active compromise evidence (execution, persistence, live process) |
LIKELY AFFECTED | §11.4 LIKELY AFFECTED | Malicious versions installed or cached; postinstall may have run |
OBSERVED ONLY | §11.5 OBSERVED ONLY | Cache/lockfile/log references; no execution evidence |
NO FINDINGS | Stop — pin versions, enable ignore-scripts, keep monitoring | None in scope |
Non-negotiable first step for any branch: verify the CLI you are about to trust is genuine. Rungenie sec verify-installbefore anyremediate,restore, orrollbackinvocation. If that call cannot return exit0, read §11.7 Escalation —--unsafe-unverifiedbefore 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 totelemetry.api-monitor.com, 143.198.237.25, and multiple *.raw.icp0.io ICP canisters. Block at the host level before scanning.
Linux — iptables
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.
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.
--apply aborts partway through, resume with:
--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.| # | Target | Rotate URL | Verification |
|---|---|---|---|
| 1 | npm token | https://www.npmjs.com/settings/~/tokens | npm whoami with new token |
| 2 | GitHub PAT + gh CLI | https://github.com/settings/tokens | gh auth status |
| 3 | AWS access keys | AWS IAM Console | aws sts get-caller-identity |
| 4 | GCP | gcloud auth revoke --all && gcloud auth login | gcloud auth list |
| 5 | Azure | az logout && az login + rotate service principals | az account show |
| 6 | Kubernetes | Rotate service-account tokens + kubeconfig contexts | kubectl auth whoami |
| 7 | Docker registries | https://hub.docker.com/settings/security (and ECR/GCR/GHCR) | docker login <registry> |
| 8 | AI provider keys (Anthropic / OpenAI / Google) | Provider console | Audit billing last 72h |
| 9 | Crypto wallets | New seed on a clean device; move funds | revoke.cash approvals audit |
| 10 | TLS private keys on host | Re-issue via your CA | Verify cert chain on endpoint |
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
@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 thescan_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
Usegenie 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.
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.
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-installexits5, 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.
--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. Thescan_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.