Uma ilustração abstrata gerada sobre um fundo azul-marinho escuro: uma pilha de cinco bandejas de memória finas em ciano vistas em corte, cada uma com fileiras de pequenos blocos cinzentos, e um pequeno cubo âmbar encaixado entre a terceira e a quarta bandeja; a partir desse cubo, um fino filamento âmbar de partículas descreve um arco para a direita através de um vazio escuro em direção a três pequenos nós vermelho-alaranjados dispostos em triângulo. Atrás das bandejas, etiquetas cinzentas ténues pendem de um porta-chaves em argolas finas. Não aparece texto, pessoas nem logótipos de organizações. O logótipo OrcaRouter está composto no canto inferior direito.
AI Safety Incidents

sckit: Os pacotes de memória de IA da MemTensor receberam backdoor para roubar credenciais e prompts de agentes

Autor

Rowan Sterling

Data de publicação

Modelos mais recentes · 20Ver todos os modelos →
Benchmarks: Artificial Analysis · atualizado diariamente
Voltar para todas as publicações

Quatro lançamentos da MemTensor publicados em 23 de setembro de 2026 carregavam o mesmo implante Go sem símbolos, e cada um deles era a versão mais recente no seu registro enquanto estava no ar. O pacote npm @memtensor/memos-cloud-openclaw-plugin foi publicado como 0.1.21 às 02:23 UTC, 0.1.23 às 03:49 e 0.1.25 às 04:36; o pacote PyPI MemoryOS foi publicado como 2.0.34 às 05:25. Todos os quatro incluíam sckit, que inicia quando o gateway do agente OpenClaw inicializa, inicia novamente a cada recuperação de memória — com o texto do prompt do usuário passado em uma variável de ambiente — e, no pacote Python, inicia com uma simples importação do módulo memos. Ele então varre o diretório home em busca de segredos de npm, PyPI, GitHub, GitLab, AWS, Vault e SSH e envia o que encontra para servidores sob skyleen[.]fr. Socket, StepSecurity, SafeDep e Aikido documentaram o comprometimento de forma independente no mesmo dia, e nenhum deles relatou evidências de que o implante tenha sido executado em um host real. O Orca AI Incident Archive mantém esta entrada na íntegra, ao lado de todos os outros incidentes de cadeia de suprimentos que registrou, e cada registro traz seu próprio grau de confiança e status de dano.

Quatro lançamentos, e um relatório público de bug no meio deles

O MemOS é o framework de memória de código aberto da MemTensor para agentes de LLM, e o pacote npm é o conector que permite a um runtime de agente OpenClaw ler e gravar em um serviço de memória hospedado; a StepSecurity observa que o mesmo pacote também declara pontos de integração para os runtimes Clawdbot e Moltbot. O Socket mediu o repositório em cerca de 11.500 estrelas e 1.100 forks quando publicou. Essa posição é o motivo pelo qual o comprometimento atraiu quatro investigações separadas: como a StepSecurity colocou, isso "coloca o plugin dentro de um processo que lida rotineiramente com entrada do usuário e pode herdar credenciais valiosas." As pessoas expostas são as que instalaram qualquer um dos pacotes — desenvolvedores em suas próprias máquinas, e executores de CI e contêineres que apenas executaram uma suíte de testes.

A sequência do npm é a parte mais clara do registro porque os carimbos de data e hora do registro são públicos e várias empresas os capturaram de forma independente. O relatório da Socket e a linha do tempo da SafeDep concordam em cada minuto: 0.1.21 às 02:23:04, 0.1.22 às 03:45:44, 0.1.23 às 03:49:20, 0.1.24 às 04:33:30 e 0.1.25 às 04:36:58. As versões 0.1.22 e 0.1.24 estavam limpas — a Socket diz que correspondiam à 0.1.20, exceto pelas strings de versão — e o payload retornou três minutos e meio após cada uma delas.

O salto de tamanho é o indício. O Socket mediu a versão 0.1.20 em cerca de 272 KB descompactados e a 0.1.21 em 43,6 MB, porque as versões maliciosas incluíam seis binários de plataforma com link estático de aproximadamente 7,4 MB cada. O PyPI mostra o mesmo padrão: o wheel 2.0.34 tinha 19.201.772 bytes contra 951.210 da versão 2.0.33, segundo o Socket.

Às 04:17 UTC — dezesseis minutos antes da versão limpa 0.1.24 e dezenove minutos antes de o payload voltar como 0.1.25 — um usuário do GitHub chamado omeridel abriu a issue #173 no repositório do plugin, intitulada "Versões maliciosas 0.1.21 e 0.1.23 publicadas no npm — token de publicação aparenta estar comprometido." A issue observa que 0.1.23 era então a tag mais recente, que nenhuma das versões correspondia a qualquer commit ou tag no repositório, e que o commit legítimo mais recente era datado de 14 de agosto. Ela permanece aberta sem comentários dos mantenedores até 26 de outubro de 2026.

A self-built HTML card headed 'Supply chain, 23 September 2026, all times UTC', titled 'Four and a half hours on npm and PyPI', subtitled 'Each malicious release was the registry's newest version while it was live'. Nine rows, each with a time, an event, a detail and a status chip: 00:48 attacker branch first pushed, pipeline; 02:23 npm 0.1.21 published, 43.6 MB unpacked up from 272 KB, malicious; 03:17 MemOS commit b52958f, six sckit binaries and a CI token stealer, malicious; 03:45 npm 0.1.22 published, matches 0.1.20 apart from version strings, clean; 03:49 npm 0.1.23 published, payload restored three minutes later, malicious; 04:17 GitHub issue 173 filed, disclosure; 04:33 npm 0.1.24 published, clean again and the latest tag for three minutes; 04:36 npm 0.1.25 published, payload back and this one takes the latest tag, malicious; 05:25 PyPI MemoryOS 2.0.34, 19.2 MB wheel against 951 KB in 2.0.33, malicious. A footer reads 'Timestamps from Socket and SafeDep, which agree to the minute. Sizes from Socket.' The OrcaRouter logo is composited in the bottom-right corner.

O que o sckit faz depois que o pacote é carregado

Nenhum dos pacotes usou um hook de instalação, e é por isso que o conselho habitual sobre --ignore-scripts não se aplicou. A análise da StepSecurity sobre a variante npm descreve um novo arquivo, lib/sckit.js, que exporta um iniciador que o código existente de inicialização e de recuperação de memória do plugin importa e chama. Na inicialização, ele inicia um processo .sckit/<os>-<arch>/sckit desanexado com stage0 --config64 e o ambiente completo do processo pai; na recuperação, faz o mesmo e passa o prompt do usuário despojado por meio de uma variável de ambiente chamada SCKIT_EVENT_TEXT. A Socket declarou a consequência sem rodeios: portanto, o binário é executado novamente a cada recuperação.

A variante do PyPI é mais curta e, na prática, mais difícil de evitar. O Socket constatou que memos/log.py chama uma função de gatilho dentro de memos/_stage0.py quando a geração de logs está configurada, que 149 módulos chamam o logger no nível do módulo e que, portanto, um simples import do módulo memos é suficiente para iniciar o payload uma vez por processo. A análise da StepSecurity do mesmo pacote foi puramente estática — ela não o instalou, importou, compilou nem executou.

O escopo de coleta é o diretório home inteiro. O SafeDep lista a raiz do inventário como $HOME e os arquivos alvo como .npmrc, .pypirc, .git-credentials, .netrc, id_rsa, id_ecdsa, id_ed25519, .vault-token, msal_token_cache, access_tokens.json e access_tokens.db, além de variáveis de ambiente cujos nomes contenham token, secret, password, API key ou URL de banco de dados, além de formatos de token reconhecidos para GitHub, GitLab, npm, PyPI, Hugging Face, Slack, Stripe, AWS e SendGrid. Os registros do OSV para os dois pacotes, MAL-2026-16476 para npm e MAL-2026-16475 para PyPI, descrevem a mesma lista de arquivos e acrescentam que o protocolo de comando e controle usa CBOR, troca de chaves X25519 e XChaCha20-Poly1305, com leases assinados e módulos entregues em tempo de execução — portanto, o conteúdo dos módulos nunca foi observado, apenas o carregador que os busca.

Dois detalhes determinam o que um defensor ainda pode recuperar. O binário contém rotinas de autodeleção chamadas scheduleSelfDelete e deleteExecutable, de acordo com o registro do OSV, e é por isso que a orientação é procurar artefatos de processo e de rede em vez de arquivos. E a versão 0.1.25 adicionou lib/tls-trust.js, que define SSL_CERT_FILE para um arquivo de autoridade certificadora com 145 certificados incluído no pacote em sistemas Linux mínimos, de acordo com a StepSecurity — uma correção destinada a fazer com que seu próprio tráfego funcione em contêineres que não possuem um armazenamento de confiança do sistema.

A generated abstract illustration on a dark navy field: at left, a dim cyan isometric tree of folders, several leaves carrying small grey key and badge silhouettes; from those keys a cluster of amber threads lifts away, braids into one bright cord and runs right through a narrow vertical cyan gateway frame that carries an amber keyhole, toward three small red-orange receivers with faint pulse rings on the far right. No text, people or organisation logos appear. The OrcaRouter logo is composited in the bottom-right corner.

O pipeline de release foi a porta de entrada

A reconstrução da SafeDep é o relato mais detalhado do acesso inicial e aponta para o GitHub Actions, e não para uma senha de registro roubada. Entre 00:48 e 02:03 UTC, uma conta do GitHub operando como Memtensor-AI criou, enviou e excluiu um branch chamado sc/release-0.1.21-20260922-cloud cinco vezes. O commit 9b97ec6 modificou o script de workflow .github/scripts/validate-release-confirmation.mjs para que ele anexasse um valor BASH_ENV a $GITHUB_ENV, o que fez com que etapas posteriores de shell não interativo carregassem um sckit-publish-bridge.sh fornecido pelo atacante antes de executar seus próprios comandos. Esse bridge verificou o nome do pacote e o tempo limite de 150 segundos da etapa de publicação, chamou o coletor de tokens com NPM_TOKEN ou NODE_AUTH_TOKEN, excluiu a si mesmo e saiu com código 1 — então a publicação falhou depois que o token foi obtido. A primeira versão maliciosa no npm apareceu vinte minutos após o último push no branch.

O caminho do PyPI usou o mesmo truque contra um pipeline diferente. O SafeDep relata que a tag v2.0.34 apontava para commits não assinados que não estavam na main, e que o commit b52958f, de autoria de "MemTensor CI Review", adicionou os seis binários, um loader Python e um backend de build personalizado chamado sckit_poetry_build. Esse backend escreveu um BASH_ENV apontando para _pypi_bridge.sh em $GITHUB_ENV; a bridge atuou apenas dentro do wrapper de upload do twine, buscou um índice assinado do host skyleen[.]fr, verificou um emissor com uma implementação Ed25519, imprimiu uma linha de marcador, removeu a senha de upload e saiu sem enviar nada. Cerca de duas horas depois, o commit 41bf5c7 removeu essa chamada com a mensagem "chore: allow native PyPI upload [skip ci]", a tag foi excluída e recriada em até dez segundos, e o upload para o PyPI ocorreu 62 segundos depois disso. O SafeDep interpreta o primeiro commit como uma execução de captura de token e o segundo como a execução que permitiu que o próprio workflow da MemTensor fizesse o build e publicasse o pacote malicioso com o token real do projeto.

Nem toda conta se encaixa nisso. A Socket observou que as versões publicadas no npm vieram da mesma conta npm que versões legítimas anteriores e não tinham gitHead, o que interpretou como indicativo de que não foram produzidas pela CI do projeto, e declarou que não conseguiu confirmar como o atacante obteve acesso de publicação. A SC Media, ao relatar as descobertas da Socket em 24 de setembro, tirou a mesma inferência de comprometimento da conta. As duas versões concordam que as credenciais de publicação foram retiradas do pipeline de release e divergem sobre como o próprio artefato npm foi produzido; ninguém publicou os logs do workflow, porque a API do GitHub Actions não mostrou execuções após 7 de setembro e a SafeDep infere que os registros foram excluídos. Como a conta Memtensor-AI obteve acesso de push em primeiro lugar é desconhecido nas duas versões; a SafeDep considera um token de conta roubado provável, mas não confirmado.

Estabelecido, inferido e ausente

A nota de confiança do registro é A e não é contestada, o que vale a pena precisar, porque a certeza se aplica ao que foi publicado e não ao que ele fez.

• Estabelecido: o conteúdo dos quatro artefatos, reconstruído por análise estática na Socket, StepSecurity e SafeDep; os horários de publicação no npm e a tag mais recente na 0.1.25; o salto de tamanho em ambos os ecossistemas; os commits, tags e histórico de branches nos dois repositórios; a infraestrutura skyleen[.]fr e os identificadores de campanha cloud-openclaw-semi-nuclear e memos-semi-nuclear; e a configuração do payload, que expira em 22–23 de outubro de 2026 de acordo com Socket e SafeDep.

• Inferido: que a ferramenta foi escrita com a ajuda de um modelo de linguagem, o que a SafeDep afirma diretamente e chama de inferência; e que os tokens de publicação roubados se destinavam a ser reutilizados, o que a string de canal da configuração — "exact-ref-one-use-NPM_TOKEN" — apoia, mas não prova.

• Não estabelecido:quem era o atacante; se alguma cópia do sckit chegou a ser executada fora de um sandbox; se alguma credencial saiu de um host; se algum prompt digitado em um agente OpenClaw chegou ao atacante; e se algum pacote downstream foi republicado. Socket e StepSecurity trabalharam ambos de forma estática, e a StepSecurity afirma que nenhuma execução de processo, nenhuma transmissão de segredo, nenhuma exfiltração bem-sucedida, nenhuma instalação de workflow e nenhuma publicação adicional de pacote foi observada em sua análise.

Essa lacuna é o motivo pelo qual o arquivo registra este incidente com o dano real marcado como falso. A exposição é real e ampla — qualquer pessoa que tenha instalado uma versão afetada é instruída a tratar o host como comprometido —, mas o dano, no sentido de uma credencial comprovadamente utilizada ou de um sistema comprovadamente alcançado, não foi registrado por nenhuma das quatro empresas que investigaram o caso.

A self-built HTML card headed 'What the record supports', titled 'Four investigating firms, no confirmed victim', subtitled 'Socket, StepSecurity, SafeDep and Aikido documented the same four artefacts on 23 September 2026'. The left column, headed 'Established by static analysis', lists: four malicious releases, npm 0.1.21, 0.1.23 and 0.1.25 and PyPI MemoryOS 2.0.34; one implant, the same stripped Go binary sckit in all four; the publish window 02:23 to 05:25 UTC with 0.1.25 tagged latest; package growth from 272 KB to 43.6 MB on npm and 951 KB to 19.2 MB for the PyPI wheel; six builds per package for Linux, macOS and Windows on amd64 and arm64; collection scoped to the whole home directory across registry, source-control, cloud, Vault and SSH secrets; exfiltration to servers under skyleen[.]fr; and OSV tracking as MAL-2026-16476 and MAL-2026-16475. The right column, headed 'Not established', lists: the attacker's identity; how Memtensor-AI obtained push access; whether any copy ever executed outside static analysis; whether a stolen secret reached the attacker; whether any prompt text was received; and whether any downstream package was republished. A footer reads 'Archive classification for this record: incident, severity high, confidence A, real harm false.' The OrcaRouter logo is composited in the bottom-right corner.

O verme que nunca foi visto se espalhar

Os binários contêm mais do que um stealer. O SafeDep lista funções chamadas recursivePublish, prepareRemoteNode, prepareRemotePython e prepareRemoteWorkflow, além de um modelo do GitHub Actions incorporado acionado no push e a capacidade de gravar um arquivo de workflow chamado runtime-update.yml em repositórios que o implante consegue alcançar. O Socket encontrou strings sobre codificação de manifestos de pacotes e instalação de arquivos de repositório e avaliou que os binários podem ser capazes de republicar pacotes usando tokens de registro roubados.

Isso é um projeto de worm. Não é um worm que tenha sido observado funcionando. A StepSecurity não encontrou evidências de que a lógica tenha sido alguma vez usada para se propagar, e a nota de pesquisa da Cloud Security Alliance de 25 de setembro interpreta a capacidade como um potencial limitado de autopropagação, em vez de comportamento de worm confirmado. Vários veículos descreveram o caso como o primeiro worm de cadeia de suprimentos voltado para infraestrutura de memória de agentes de IA; a descrição é adequada como uma afirmação sobre o projeto, e os relatórios não a sustentam como uma afirmação sobre o que aconteceu.

O que mudou depois

Os registros foram limpos no mesmo dia. Verificado em 26 de outubro de 2026, os metadados do pacote npm não listam mais 0.1.21, 0.1.23 ou 0.1.25 entre suas versões, a tag latest aponta para 0.1.24, e o pacote foi modificado pela última vez às 11:53 UTC de 23 de setembro. Duas dist-tags incomuns ainda estão anexadas — clean-inverse-0-1-23 apontando para 0.1.22 e clean-inverse-0-1-25 apontando para 0.1.24 — espelhando as duas versões limpas que interromperam brevemente as maliciosas. No PyPI, o MemoryOS 2.0.34 não está mais disponível e a versão mais recente é a 2.0.33, enviada em 3 de setembro de 2026; não houve nenhum outro lançamento no PyPI nas sete semanas seguintes.

O que não mudou é a versão pública do projeto. O repositório não lista nenhum aviso de segurança, a issue do GitHub das 04:17 do dia do incidente continua aberta e sem resposta, e nenhuma das reportagens aqui analisadas cita uma declaração da MemTensor ou da OpenClaw. Nenhum dos dois pacotes maliciosos trazia uma atestação de proveniência, o que, segundo a SafeDep, removeu o único indício de que os artefatos haviam sido criados a partir de um commit inesperado.

A resposta que existe está do lado da detecção: a StepSecurity adicionou os domínios de comando e controle skyleen[.]fr à sua lista de bloqueio global, e os dois pacotes são rastreados no OSV como MAL-2026-16476 e MAL-2026-16475.

Se uma versão afetada estiver instalada

A orientação da Socket é a mais rigorosa e a mais simples: se qualquer versão listada foi carregada ou importada, considere esse host comprometido, incluindo runners de CI e contêineres que apenas executaram testes. Os passos concretos em que as quatro empresas convergem:

• Remova o pacote e fixe em uma versão limpa — npm 0.1.20, PyPI 2.0.33. A StepSecurity adverte que sua análise não estabeleceu uma linha de base limpa do PyPI, enquanto SafeDep e SC Media citam ambas 2.0.33 como a última versão boa.

• Procure a linha de comando do processo, pois o executável pode se excluir: sckit stage0 --config64, e a variável de ambiente SCKIT_EVENT_TEXT.

• Exclua os diretórios de estado ~/.openclaw/.cache/runtime e ~/.memos/.cache/runtime, e verifique nos repositórios se há um runtime-update.yml fluxo de trabalho inesperado ou diretórios .sckit/.

• Rode todas as credenciais acessíveis a partir do diretório home e do ambiente de processo, a partir de uma máquina limpa: npm, PyPI, GitHub, GitLab, AWS, Vault, SSH, Hugging Face, Slack, Stripe e SendGrid, e quaisquer valores de .env. Tokens de registro e de controle de código-fonte vêm primeiro.

• Revise os lançamentos dos seus próprios pacotes, caso um token de publicação roubado tenha sido usado para publicar versões que você não escreveu.

• Bloqueie skyleen[.]fr e seus subdomínios, e leia os logs de saída retroativamente até 23 de setembro.

• Trate qualquer prompt ou segredo colado que tenha passado pelo plugin enquanto ele estava ativo como exposto. Esta é a parte do incidente específica da memória do agente: o implante não precisava extrair uma transcrição, porque a transcrição lhe era entregue a cada recordação.