Un'illustrazione astratta generata su un fondo blu navy scuro: una pila di cinque sottili vassoi di memoria ciano visti in sezione, ciascuno contenente file di piccoli blocchi grigi, con un piccolo cubo ambrato inserito tra il terzo e il quarto vassoio; da quel cubo un sottile filamento ambrato di particelle si inarca verso destra attraverso un vuoto scuro verso tre piccoli nodi rosso-arancio disposti a triangolo. Dietro i vassoi, etichette grigie fioche pendono da un portachiavi su anelli sottili. Non compaiono testi, persone o loghi di organizzazioni. Il logo OrcaRouter è sovrapposto nell'angolo in basso a destra.
AI Safety Incidents

sckit: i pacchetti di memoria AI di MemTensor sono stati compromessi con backdoor per rubare credenziali e prompt degli agenti

Autore

Rowan Sterling

Data di pubblicazione

Ultimi modelli · 20Vedi tutti i modelli →
Benchmark: Artificial Analysis · aggiornato ogni giorno
Torna a tutti gli articoli

Quattro release MemTensor pubblicate il 23 settembre 2026 contenevano lo stesso implant Go in versione stripped, e ciascuna era la versione più recente sul proprio registry mentre era attiva. Il pacchetto npm @memtensor/memos-cloud-openclaw-plugin è uscito come 0.1.21 alle 02:23 UTC, 0.1.23 alle 03:49 e 0.1.25 alle 04:36; il pacchetto PyPI MemoryOS è uscito come 2.0.34 alle 05:25. Tutte e quattro distribuivano sckit, che si avvia all'avvio del gateway dell'agente OpenClaw, si avvia di nuovo a ogni richiamo della memoria — con il testo del prompt dell'utente passato in una variabile d'ambiente — e, nel pacchetto Python, si avvia con un semplice import del modulo memos. Poi scandaglia la directory home alla ricerca di segreti npm, PyPI, GitHub, GitLab, AWS, Vault e SSH e invia ciò che trova a server nel dominio skyleen[.]fr. Socket, StepSecurity, SafeDep e Aikido hanno documentato la compromissione in modo indipendente quel giorno, e nessuno di loro ha riportato prove che l'implant fosse stato eseguito su un host reale. L'Orca AI Incident Archive contiene questa voce per intero, insieme a ogni altro incidente della supply chain che ha registrato, e ogni record riporta il proprio grado di confidenza e stato di danno.

Quattro release, e una segnalazione di bug pubblica nel bel mezzo

MemOS è il framework di memoria open source di MemTensor per gli agenti LLM, e il pacchetto npm è il connettore che consente a un runtime di agente OpenClaw di leggere e scrivere su un servizio di memoria ospitato; StepSecurity osserva che lo stesso pacchetto dichiara anche punti di integrazione per i runtime Clawdbot e Moltbot. Socket ha misurato il repository a circa 11.500 stelle e 1.100 fork al momento della pubblicazione. Tale posizione è il motivo per cui la compromissione ha attirato quattro indagini separate: come ha detto StepSecurity, questo "colloca il plugin all'interno di un processo che gestisce regolarmente input degli utenti e potrebbe ereditare credenziali di valore". Le persone esposte sono coloro che hanno installato l'uno o l'altro pacchetto — sviluppatori sulle proprie macchine, e runner CI e container che hanno eseguito solo una suite di test.

La sequenza npm è la parte più chiara del record perché i timestamp del registry sono pubblici e diverse società li hanno registrati in modo indipendente. Il resoconto di Socket e la cronologia di SafeDep concordano su ogni minuto: 0.1.21 alle 02:23:04, 0.1.22 alle 03:45:44, 0.1.23 alle 03:49:20, 0.1.24 alle 04:33:30 e 0.1.25 alle 04:36:58. Le versioni 0.1.22 e 0.1.24 erano pulite — Socket afferma che corrispondevano alla 0.1.20 a parte le stringhe di versione — e il payload è ricomparso tre minuti e mezzo dopo ciascuna di esse.

Il salto di dimensione è l'indizio. Socket ha misurato 0.1.20 a circa 272 KB non decompresso e 0.1.21 a 43,6 MB, perché le release dannose includevano sei binari di piattaforma con link statico di circa 7,4 MB ciascuno. PyPI mostra lo stesso schema: la wheel 2.0.34 era di 19.201.772 byte contro 951.210 per la 2.0.33, secondo Socket.

Alle 04:17 UTC — sedici minuti prima della versione pulita 0.1.24 e diciannove prima che il payload tornasse come 0.1.25 — un utente GitHub di nome omeridel ha aperto la issue #173 sul repository del plugin, intitolata "Versioni malevole 0.1.21 e 0.1.23 pubblicate su npm — il token di pubblicazione sembra compromesso". La issue rileva che 0.1.23 era allora l'ultimo tag, che nessuna delle due versioni corrispondeva ad alcun commit o tag nel repository e che il commit legittimo più recente era datato 14 agosto. Rimane aperta senza commenti da parte dei manutentori al 26 ottobre 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.

Cosa fa sckit una volta che il pacchetto è stato caricato

Nessuno dei due pacchetti utilizzava un hook di installazione, ed è per questo che il consueto consiglio su --ignore-scripts non si applicava. L'analisi di StepSecurity della variante npm descrive un nuovo file, lib/sckit.js, che esporta un launcher che il codice esistente di avvio e di richiamo della memoria del plugin importa e chiama. All'avvio genera un processo .sckit/<os>-<arch>/sckit distaccato con stage0 --config64 e l'intero ambiente del processo padre; al richiamo fa lo stesso e passa il prompt utente ripulito tramite una variabile d'ambiente denominata SCKIT_EVENT_TEXT. Socket ha messo la conseguenza in modo chiaro: il binario, quindi, viene eseguito di nuovo a ogni richiamo.

La variante PyPI è più breve e, in pratica, più difficile da evitare. Socket ha scoperto che memos/log.py chiama una funzione di attivazione all'interno di memos/_stage0.py quando la registrazione dei log è configurata, che 149 moduli chiamano il logger a livello di modulo e che quindi una semplice importazione del modulo memos è sufficiente per avviare il payload una volta per processo. L'analisi di StepSecurity dello stesso pacchetto è stata puramente statica: non lo ha installato, importato, compilato né eseguito.

L'ambito di raccolta è l'intera directory home. SafeDep elenca la radice dell'inventario come $HOME e i file presi di mira come .npmrc, .pypirc, .git-credentials, .netrc, id_rsa, id_ecdsa, id_ed25519, .vault-token, msal_token_cache, access_tokens.json e access_tokens.db, oltre a variabili d'ambiente i cui nomi contengono token, secret, password, API key o URL del database, oltre ai formati di token riconosciuti per GitHub, GitLab, npm, PyPI, Hugging Face, Slack, Stripe, AWS e SendGrid. I record OSV per i due pacchetti, MAL-2026-16476 per npm e MAL-2026-16475 per PyPI, descrivono lo stesso elenco di file e aggiungono che il protocollo command-and-control usa CBOR, scambio di chiavi X25519 e XChaCha20-Poly1305, con lease firmati e moduli forniti a runtime — quindi i contenuti dei moduli non sono mai stati osservati, solo il loader che li recupera.

Due dettagli determinano ciò che un difensore può ancora recuperare. Il binario contiene routine di autoeliminazione denominate scheduleSelfDelete e deleteExecutable, secondo il record OSV, motivo per cui l'indicazione è cercare artefatti di processo e di rete anziché file. E la 0.1.25 ha aggiunto lib/tls-trust.js, che imposta SSL_CERT_FILE su un file bundle di 145 autorità di certificazione sui sistemi Linux minimali, secondo StepSecurity — una correzione volta a far funzionare il proprio traffico su container privi di un archivio di fiducia di 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.

La pipeline di rilascio è stata la via d’accesso.

La ricostruzione di SafeDep è il resoconto più dettagliato dell'accesso iniziale e indica GitHub Actions anziché una password del registry rubata. Tra 00:48 e 02:03 UTC, un account GitHub che operava come Memtensor-AI ha creato, ha fatto push e ha eliminato un branch denominato sc/release-0.1.21-20260922-cloud cinque volte. Il commit 9b97ec6 ha modificato lo script del workflow .github/scripts/validate-release-confirmation.mjs in modo che aggiungesse in coda un valore BASH_ENV a $GITHUB_ENV, il che faceva sì che i successivi passaggi di shell non interattivi eseguissero tramite source uno script fornito dall'attaccante, sckit-publish-bridge.sh prima di eseguire i propri comandi. Quel bridge verificava il nome del pacchetto e il timeout di 150 secondi del passaggio di pubblicazione, chiamava il raccoglitore di token con NPM_TOKEN o NODE_AUTH_TOKEN, si eliminava e usciva con 1 — quindi la pubblicazione è fallita dopo che il token era stato prelevato. La prima release npm dannosa è apparsa venti minuti dopo l'ultimo push del branch.

Il percorso PyPI ha usato lo stesso trucco contro una pipeline diversa. SafeDep segnala che il tag v2.0.34 puntava a commit non firmati che non erano su main, e che il commit b52958f, attribuito a "MemTensor CI Review", ha aggiunto i sei binari, un loader Python e un backend di build personalizzato chiamato sckit_poetry_build. Quel backend ha scritto un BASH_ENV che puntava a _pypi_bridge.sh in $GITHUB_ENV; il bridge ha agito solo all'interno del wrapper di upload di twine, ha recuperato un indice firmato dall'host skyleen[.]fr, ha verificato un emettitore con un'implementazione Ed25519, ha stampato una riga di marcatura, ha rimosso la password di upload ed è uscito senza caricare nulla. Circa due ore dopo, il commit 41bf5c7 ha rimosso quella chiamata con il messaggio "chore: allow native PyPI upload [skip ci]", il tag è stato eliminato e ricreato nel giro di dieci secondi, e l'upload su PyPI è avvenuto 62 secondi dopo. SafeDep interpreta il primo commit come un'esecuzione di cattura del token e il secondo come l'esecuzione che ha consentito al workflow stesso di MemTensor di compilare e pubblicare il pacchetto malevolo con il token reale del progetto.

Non tutti gli account concordano su questo punto. Socket ha osservato che le release npm provenivano dallo stesso account npm delle precedenti versioni legittime ed erano prive di un gitHead, cosa che ha interpretato come segno che non fossero state prodotte dalla CI del progetto, e ha dichiarato di non poter confermare in che modo l'attaccante abbia ottenuto l'accesso per la pubblicazione. SC Media, riportando le conclusioni di Socket il 24 settembre, ha tratto la stessa inferenza verso una compromissione dell'account. Le due versioni concordano sul fatto che le credenziali di pubblicazione siano state sottratte alla pipeline di rilascio e divergono su come sia stato prodotto l'artefatto npm stesso; nessuno ha pubblicato i log dei workflow, perché l'API Actions di GitHub non mostrava esecuzioni dopo il 7 settembre e SafeDep deduce che i registri siano stati eliminati. In entrambe le versioni non è noto in che modo l'account Memtensor-AI abbia ottenuto l'accesso push; SafeDep ritiene probabile, ma non confermato, che sia stato rubato un token dell'account.

Stabilito, dedotto e assente

Il grado di affidabilità del record è A e non è contestato, il che merita di essere precisato, perché la certezza riguarda ciò che è stato pubblicato e non ciò che ha fatto.

• Accertato: i contenuti dei quattro artefatti, ricostruiti tramite analisi statica presso Socket, StepSecurity e SafeDep; gli orari di pubblicazione su npm e il tag latest sulla 0.1.25; l'aumento di dimensione in entrambi gli ecosistemi; i commit, i tag e la cronologia dei branch nei due repository; l'infrastruttura skyleen[.]fr e gli identificatori della campagna cloud-openclaw-semi-nuclear e memos-semi-nuclear; e la configurazione del payload, che scade tra il 22 e il 23 ottobre 2026 secondo Socket e SafeDep.

• Dedotto: che lo strumento sia stato scritto con l'aiuto di un modello linguistico, cosa che SafeDep afferma direttamente e definisce un'inferenza; e che i token di pubblicazione rubati fossero destinati a essere riutilizzati, cosa che la stringa del canale della configurazione — "exact-ref-one-use-NPM_TOKEN" — supporta ma non prova.

• Non stabilito: chi fosse l'attaccante; se qualche copia di sckit sia mai stata eseguita al di fuori di una sandbox; se qualche credenziale abbia lasciato un host; se qualche prompt digitato in un agente OpenClaw abbia raggiunto l'attaccante; e se qualche pacchetto downstream sia stato ripubblicato. Socket e StepSecurity hanno entrambi operato in modo statico, e StepSecurity afferma che nella sua analisi non è stata osservata alcuna esecuzione di processo, alcuna trasmissione di segreti, alcuna esfiltrazione riuscita, alcuna installazione di workflow e alcuna ulteriore pubblicazione di pacchetti.

È per questa lacuna che l’archivio registra questo incidente indicando il danno reale come falso. L’esposizione è reale e ampia — a chiunque abbia installato una versione interessata viene detto di trattare l’host come compromesso — ma nessuna delle quattro società che hanno svolto le indagini ha registrato un danno, nel senso di una credenziale dimostrabilmente utilizzata o di un sistema dimostrabilmente raggiunto.

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.

Il verme che non è mai stato visto diffondersi

I binari contengono più di un semplice stealer. SafeDep elenca funzioni denominate recursivePublish, prepareRemoteNode, prepareRemotePython e prepareRemoteWorkflow, oltre a un template GitHub Actions incorporato attivato al push e la capacità di scrivere un file di workflow chiamato runtime-update.yml nei repository raggiungibili dall'impianto. Socket ha trovato stringhe relative alla codifica dei manifest dei pacchetti e all'installazione di file di repository e ha valutato che i binari potrebbero essere in grado di ripubblicare pacchetti usando token di registry rubati.

Quello è un progetto di worm. Non è un worm che sia stato osservato in azione. StepSecurity non ha trovato alcuna prova che la logica sia mai stata usata per propagarsi, e la nota di ricerca della Cloud Security Alliance del 25 settembre interpreta la capacità come un potenziale limitato di auto-propagazione anziché come un comportamento da worm confermato. Diverse testate hanno descritto il caso come il primo worm della catena di approvvigionamento mirato all'infrastruttura di memoria degli agenti AI; la descrizione è corretta come affermazione sul progetto, e i rapporti non la sostengono come affermazione su ciò che è accaduto.

Cosa è cambiato in seguito

I registri sono stati ripuliti lo stesso giorno. Verificato il 26 ottobre 2026, i metadati del pacchetto npm non elencano più 0.1.21, 0.1.23 o 0.1.25 tra le sue versioni, il tag latest punta a 0.1.24 e il pacchetto è stato modificato l'ultima volta alle 11:53 UTC del 23 settembre. Sono ancora presenti due dist-tag insoliti — clean-inverse-0-1-23 che punta a 0.1.22 e clean-inverse-0-1-25 che punta a 0.1.24 — a rispecchiare le due release pulite che hanno brevemente interrotto quelle malevole. Su PyPI, MemoryOS 2.0.34 non c'è più e la release più recente è 2.0.33, caricata il 3 settembre 2026; non ci sono state altre release su PyPI nelle sette settimane successive.

Ciò che non è cambiato è la versione pubblica del progetto. Il repository non elenca alcun avviso di sicurezza, la issue su GitHub delle 04:17 del giorno dell'incidente è ancora aperta e senza risposta, e nessuno dei resoconti esaminati qui cita una dichiarazione di MemTensor o di OpenClaw. Nessuno dei due pacchetti malevoli era corredato di un'attestazione di provenienza, il che, come osserva SafeDep, ha eliminato l'unico segnale del fatto che gli artefatti fossero stati costruiti da un commit inatteso.

La risposta che effettivamente esiste è sul versante del rilevamento: StepSecurity ha aggiunto i domini di comando e controllo skyleen[.]fr alla propria blocklist globale, e i due pacchetti sono tracciati in OSV come MAL-2026-16476 e MAL-2026-16475.

Se è stata installata una versione interessata

Le indicazioni di Socket sono le più rigorose e le più semplici: se è stata caricata o importata una qualsiasi delle versioni elencate, considera compromesso quel host, compresi i runner CI e i container che hanno eseguito solo i test. I passaggi concreti sui quali convergono le quattro aziende:

• {{1}}Rimuovere il pacchetto e fissarlo a una versione pulita{{/1}} — npm {{2}}0.1.20{{/2}}, PyPI {{3}}2.0.33{{/3}}. {{4}}StepSecurity avverte che la sua analisi non ha stabilito una baseline PyPI pulita, mentre SafeDep e SC Media indicano entrambi la {{5}}2.0.33{{/5}} come l'ultima release valida.{{/4}}

• Cerca la riga di comando del processo, poiché l'eseguibile potrebbe eliminarsi da solo: sckit stage0 --config64, e la variabile d'ambiente SCKIT_EVENT_TEXT.

• Elimina le directory di stato ~/.openclaw/.cache/runtime e ~/.memos/.cache/runtime, e controlla nei repository la presenza di un inatteso runtime-update.yml workflow o della directory .sckit/.

• Ruota ogni credenziale raggiungibile dalla directory home e dall'ambiente di processo, da una macchina pulita: npm, PyPI, GitHub, GitLab, AWS, Vault, SSH, Hugging Face, Slack, Stripe e SendGrid, e qualsiasi valore .env. I token dei registry e del controllo del codice sorgente vanno per primi.

• Controlla le release dei tuoi pacchetti, nel caso in cui un token di pubblicazione rubato sia stato usato per distribuire versioni che non hai scritto.

• Blocca skyleen[.]fr e i relativi sottodomini e leggi i log del traffico in uscita fino al 23 settembre.

• Considera esposto qualsiasi prompt o segreto incollato che sia passato attraverso il plugin mentre era attivo. Questa è la parte dell'incidente specifica della memoria dell'agente: l'implant non aveva bisogno di estrarre una trascrizione, perché la trascrizione gli veniva consegnata a ogni richiamo.