Wygenerowana abstrakcyjna ilustracja na ciemnogranatowym tle: stos pięciu cienkich cyjanowych tac pamięci widocznych w przekroju, z których każda mieści rzędy małych szarych bloków, a jeden mały bursztynowy sześcian wsunięto między trzecią a czwartą tacę; z tego sześcianu cienka bursztynowa nić cząstek zatacza łuk w prawo przez ciemną pustkę w stronę trzech małych czerwono-pomarańczowych węzłów ułożonych w trójkąt. Za tacami, na cienkich pętlach, z pierścienia do kluczy zwisają przygaszone szare metki. Nie pojawia się żaden tekst, ludzie ani logotypy organizacji. Logo OrcaRouter jest nałożone w prawym dolnym rogu.
AI Safety Incidents

sckit: Pakiety pamięci AI MemTensor zostały zainfekowane backdoorami, aby wykradać poświadczenia agentów i prompty

Autor

Rowan Sterling

Data publikacji

Najnowsze modele · 20Zobacz wszystkie modele →
Benchmarki: Artificial Analysis · aktualizowane codziennie
Powrót do wszystkich wpisów

Cztery wydania MemTensor opublikowane 23 września 2026 zawierały ten sam okrojony implant Go, a każde z nich było najnowszą wersją w swoim rejestrze w czasie, gdy było dostępne. Wtyczka npm @memtensor/memos-cloud-openclaw-plugin została opublikowana jako 0.1.21 o 02:23 UTC, 0.1.23 o 03:49 i 0.1.25 o 04:36; pakiet PyPI MemoryOS został opublikowany jako 2.0.34 o 05:25. Wszystkie cztery zawierały sckit, który uruchamia się przy starcie bramy agenta OpenClaw, uruchamia się ponownie przy każdym przywołaniu pamięci — z tekstem promptu użytkownika przekazanym w zmiennej środowiskowej — a w pakiecie Python uruchamia się przy zwykłym imporcie modułu memos. Następnie przeczesuje katalog domowy w poszukiwaniu sekretów npm, PyPI, GitHub, GitLab, AWS, Vault i SSH i wysyła to, co znajdzie, na serwery w domenie skyleen[.]fr. Socket, StepSecurity, SafeDep i Aikido niezależnie udokumentowały to naruszenie tego samego dnia, a żaden z nich nie zgłosił dowodów, że implant uruchomił się na rzeczywistym hoście. Archiwum incydentów Orca AI przechowuje ten wpis w całości, obok wszystkich innych zarejestrowanych przez nie incydentów w łańcuchu dostaw, a każdy rekord ma własną ocenę pewności i status szkodliwości.

Cztery wydania, a pomiędzy nimi publiczne zgłoszenie błędu

MemOS to open-source’owy framework pamięci firmy MemTensor dla agentów LLM, a pakiet npm to łącznik, który pozwala środowisku uruchomieniowemu agenta OpenClaw odczytywać i zapisywać dane w hostowanej usłudze pamięci; StepSecurity zauważa, że ten sam pakiet deklaruje również punkty integracji ze środowiskami uruchomieniowymi Clawdbot i Moltbot. Socket zmierzył repozytorium na około 11 500 gwiazdek i 1 100 forków w momencie publikacji. Ta pozycja sprawiła, że kompromitacja wywołała cztery osobne dochodzenia: jak ujął to StepSecurity, umieszcza to „wtyczkę w procesie, który rutynowo obsługuje dane wejściowe użytkownika i może dziedziczyć cenne poświadczenia”. Osoby narażone to te, które zainstalowały którykolwiek z pakietów — deweloperzy na własnych maszynach oraz runnerzy CI i kontenery, które uruchamiały jedynie zestaw testów.

Sekwencja npm jest najbardziej klarowną częścią zapisu, ponieważ znaczniki czasu rejestru są publiczne, a kilka firm niezależnie je przechwyciło. Opracowanie Socket i oś czasu SafeDep zgadzają się co do minuty: 0.1.21 o 02:23:04, 0.1.22 o 03:45:44, 0.1.23 o 03:49:20, 0.1.24 o 04:33:30 i 0.1.25 o 04:36:58. Wersje 0.1.22 i 0.1.24 były czyste — według Socket różniły się od 0.1.20 tylko ciągami wersji — a ładunek powrócił trzy i pół minuty po każdej z nich.

Skok rozmiaru jest wskazówką. Socket zmierzył 0.1.20 na około 272 KB po rozpakowaniu, a 0.1.21 na 43,6 MB, ponieważ złośliwe wydania zawierały sześć statycznie linkowanych binariów platformowych o rozmiarze około 7,4 MB każde. PyPI pokazuje ten sam wzorzec: pakiet wheel 2.0.34 miał 19 201 772 bajtów w porównaniu z 951 210 dla 2.0.33, według Socket.

O 04:17 UTC — szesnaście minut przed czystą wersją 0.1.24 i dziewiętnaście przed tym, jak payload wrócił jako 0.1.25 — użytkownik GitHuba o nazwie omeridel otworzył zgłoszenie #173 w repozytorium wtyczki, zatytułowane „Złośliwe wersje 0.1.21 i 0.1.23 opublikowane w npm — token publikacji wygląda na skompromitowany”. W zgłoszeniu zauważono, że 0.1.23 była wówczas najnowszym tagiem, że żadna z tych wersji nie odpowiadała żadnemu commitowi ani tagowi w repozytorium oraz że najnowszy legalny commit był datowany na 14 sierpnia. Pozostaje otwarte bez komentarzy od opiekunów według stanu na 26 października 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.

Co sckit robi po załadowaniu pakietu

Żaden z pakietów nie używał hooka instalacyjnego, dlatego zwykła rada dotycząca --ignore-scripts nie miała zastosowania. Analiza wariantu npm przeprowadzona przez StepSecurity opisuje nowy plik lib/sckit.js, eksportujący program uruchamiający, który istniejący kod startowy i kod przywoływania z pamięci wtyczki importuje i wywołuje. Przy starcie uruchamia odłączony proces .sckit/<os>-<arch>/sckit z stage0 --config64 i pełnym środowiskiem rodzica; przy przywoływaniu robi to samo i przekazuje oczyszczony prompt użytkownika przez zmienną środowiskową o nazwie SCKIT_EVENT_TEXT. Socket ujął konsekwencję wprost: binarka uruchamia się zatem ponownie przy każdym przywołaniu.

Wariant w PyPI jest krótszy i w praktyce trudniejszy do uniknięcia. Socket ustalił, że memos/log.py wywołuje funkcję wyzwalającą wewnątrz memos/_stage0.py po skonfigurowaniu logowania, że 149 modułów wywołuje logger na poziomie modułu, a zatem zwykły import modułu memos wystarcza, by uruchomić payload raz na proces. Analiza tego samego pakietu przeprowadzona przez StepSecurity miała charakter wyłącznie statyczny — nie instalowała, nie importowała, nie budowała ani nie uruchamiała go.

Zakres zbierania obejmuje cały katalog domowy. SafeDep podaje katalog główny inwentarza jako $HOME i wskazane pliki jako .npmrc, .pypirc, .git-credentials, .netrc, id_rsa, id_ecdsa, id_ed25519, .vault-token, msal_token_cache, access_tokens.json oraz access_tokens.db, a także zmienne środowiskowe, których nazwy zawierają token, secret, password, API key lub database URL, oraz rozpoznawane formaty tokenów dla GitHub, GitLab, npm, PyPI, Hugging Face, Slack, Stripe, AWS i SendGrid. Rekordy OSV dla obu pakietów, MAL-2026-16476 dla npm i MAL-2026-16475 dla PyPI, opisują tę samą listę plików i dodają, że protokół command-and-control wykorzystuje CBOR, wymianę kluczy X25519 i XChaCha20-Poly1305, z podpisanymi dzierżawami i modułami dostarczanymi w czasie działania — więc zawartości modułów nigdy nie zaobserwowano, jedynie loader, który je pobiera.

Dwa szczegóły kształtują to, co obrońca może jeszcze odzyskać. Plik binarny zawiera procedury samousuwania o nazwach scheduleSelfDelete i deleteExecutable, według zapisu OSV, dlatego wskazówki mówią, aby tropić artefakty procesów i sieci, a nie pliki. Wersja 0.1.25 dodała lib/tls-trust.js, który ustawia SSL_CERT_FILE na dołączony plik 145 urzędów certyfikacji w minimalnych systemach Linux, według StepSecurity — poprawka mająca sprawić, by jego własny ruch działał w kontenerach pozbawionych systemowego magazynu zaufania.

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.

Potok wydawniczy był sposobem na wejście

Rekonstrukcja SafeDep jest najbardziej szczegółowym opisem początkowego dostępu i wskazuje na GitHub Actions, a nie na skradzione hasło do rejestru. Między 00:48 i 02:03 UTC konto GitHub działające jako Memtensor-AI utworzyło, wypchnęło i usunęło gałąź o nazwie sc/release-0.1.21-20260922-cloud pięć razy. Commit 9b97ec6 zmodyfikował skrypt workflow .github/scripts/validate-release-confirmation.mjs tak, że dołączał wartość BASH_ENV do $GITHUB_ENV, co powodowało, że późniejsze nieinteraktywne kroki powłoki uruchamiały dostarczony przez atakującego skrypt sckit-publish-bridge.sh przed wykonaniem własnych poleceń. Ten bridge sprawdzał nazwę pakietu i 150-sekundowy limit czasu kroku publikacji, wywoływał kolektor tokenów z NPM_TOKEN lub NODE_AUTH_TOKEN, usuwał się i kończył z kodem 1 — więc publikacja nie powiodła się po przejęciu tokenu. Pierwsze złośliwe wydanie npm pojawiło się dwadzieścia minut po ostatnim wypchnięciu gałęzi.

Ścieżka PyPI wykorzystała ten sam trik przeciwko innemu potokowi. SafeDep donosi, że tag v2.0.34 wskazywał na niepodpisane commity, których nie było w gałęzi main, a commit b52958f, którego autorem był „MemTensor CI Review”, dodał sześć plików binarnych, loader w Pythonie i niestandardowy backend budowania o nazwie sckit_poetry_build. Ten backend zapisał do $GITHUB_ENV zmienną BASH_ENV wskazującą na _pypi_bridge.sh; bridge działał wyłącznie wewnątrz wrappera uploadu twine, pobrał podpisany indeks z hosta skyleen[.]fr, zweryfikował emitter za pomocą implementacji Ed25519, wypisał linię znacznika, usunął hasło do uploadu i zakończył się, niczego nie wysyłając. Około dwie godziny później commit 41bf5c7 usunął to wywołanie z komunikatem „chore: allow native PyPI upload [skip ci]”, tag został usunięty i odtworzony w ciągu dziesięciu sekund, a upload do PyPI nastąpił 62 sekundy później. SafeDep odczytuje pierwszy commit jako przebieg przechwytujący token, a drugi jako przebieg, który pozwolił własnemu workflow MemTensor zbudować i opublikować złośliwy pakiet przy użyciu prawdziwego tokena projektu.

Nie wszystkie relacje są w tej kwestii zgodne. Socket zauważył, że wydania npm pochodziły z tego samego konta npm co wcześniejsze legalne wersje i nie miały gitHead, co odczytał jako oznakę, że nie zostały wytworzone przez CI projektu, i stwierdził, że nie potrafi potwierdzić, w jaki sposób atakujący uzyskał dostęp do publikowania. SC Media, relacjonując 24 września ustalenia Socket, wyciągnęło ten sam wniosek o przejęciu konta. Obie wersje zgadzają się, że poświadczenia do publikowania zostały przejęte z potoku wydawniczego, a różnią się co do tego, jak sam artefakt npm został wytworzony; nikt nie opublikował logów przepływu pracy, ponieważ API GitHub Actions nie pokazało żadnych uruchomień po 7 września, a SafeDep wnioskuje, że rekordy zostały usunięte. W jaki sposób konto Memtensor-AI uzyskało uprawnienia do pushowania w pierwszej kolejności, nie jest znane w obu relacjach; SafeDep uznaje skradziony token konta za prawdopodobny, ale niepotwierdzony.

Ustalony, wywnioskowany i nieobecny

Ocena pewności tego zapisu to A i nie jest ona kwestionowana, co warto dokładnie zaznaczyć, ponieważ pewność odnosi się do tego, co opublikowano, a nie do tego, co ów zapis zrobił.

• Ustalono: zawartość czterech artefaktów, zrekonstruowaną przez analizę statyczną w Socket, StepSecurity i SafeDep; czasy publikacji w npm oraz najnowszy tag w wersji 0.1.25; skok rozmiaru w obu ekosystemach; historię commitów, tagów i gałęzi w obu repozytoriach; infrastrukturę skyleen[.]fr oraz identyfikatory kampanii cloud-openclaw-semi-nuclear i memos-semi-nuclear; a także konfigurację payloadu, która według Socket i SafeDep wygasa 22–23 października 2026 r.

• Wywnioskowano: że narzędzie zostało napisane z pomocą modelu językowego, co SafeDep mówi wprost i nazywa wnioskiem; oraz że skradzione tokeny publikacji miały zostać ponownie użyte, co ciąg kanału w konfiguracji — „exact-ref-one-use-NPM_TOKEN” — wspiera, ale nie dowodzi.

• Nie ustalono:kim był atakujący; czy jakakolwiek kopia sckit została kiedykolwiek uruchomiona poza piaskownicą; czy jakiekolwiek poświadczenie opuściło hosta; czy jakikolwiek prompt wpisany do agenta OpenClaw dotarł do atakującego; oraz czy jakikolwiek pakiet zależny został ponownie opublikowany. Socket i StepSecurity przeprowadziły analizę statyczną, a StepSecurity stwierdza, że w ramach jej analizy nie zaobserwowano uruchomienia żadnego procesu, transmisji żadnego sekretu, udanej eksfiltracji, instalacji żadnego workflow ani dalszej publikacji pakietów.

Ta luka jest powodem, dla którego archiwum rejestruje ten incydent z rzeczywistymi szkodami oznaczonymi jako fałszywe. Ekspozycja jest realna i szeroka — każdy, kto zainstalował podatną wersję, jest informowany, by traktować hosta jako skompromitowany — ale żadna z czterech firm prowadzących dochodzenie nie odnotowała szkód w rozumieniu udowodnionego użycia poświadczeń lub udowodnionego dotarcia do systemu.

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.

Robak, którego rozprzestrzeniania się nigdy nie zaobserwowano

Binaria zawierają więcej niż stealer. SafeDep wymienia funkcje o nazwach recursivePublish, prepareRemoteNode, prepareRemotePython i prepareRemoteWorkflow, a także osadzony szablon GitHub Actions wyzwalany przy push oraz możliwość zapisania pliku przepływu pracy o nazwie runtime-update.yml w repozytoriach, do których implant ma dostęp. Socket znalazł ciągi znaków dotyczące kodowania manifestów pakietów i instalowania plików repozytorium oraz ocenił, że binaria mogą być w stanie ponownie publikować pakiety przy użyciu skradzionych tokenów rejestru.

To projekt robaka. Nie jest to robak, którego działanie zaobserwowano. StepSecurity nie znalazło dowodów na to, że logika ta kiedykolwiek została wykorzystana do propagacji, a notatka badawcza Cloud Security Alliance z 25 września odczytuje tę zdolność jako ograniczony potencjał samopropagacji, a nie potwierdzone zachowanie robaka. Kilka mediów opisało ten przypadek jako pierwszego robaka w łańcuchu dostaw wymierzonego w infrastrukturę pamięci agentów AI; opis ten jest zasadny jako stwierdzenie o projekcie, a raporty nie wspierają go jako stwierdzenia o tym, co się wydarzyło.

Co się potem zmieniło?

Rejestry zostały wyczyszczone tego samego dnia. Po sprawdzeniu 26 października 2026 r. metadane pakietu npm nie zawierają już wersji 0.1.21, 0.1.23 ani 0.1.25, tag latest wskazuje na 0.1.24, a pakiet został ostatnio zmodyfikowany o 11:53 UTC 23 września. Wciąż przypisane są dwa nietypowe tagi dist — clean-inverse-0-1-23 wskazujący na 0.1.22 i clean-inverse-0-1-25 wskazujący na 0.1.24 — odzwierciedlające dwa czyste wydania, które na krótko przerwały serię złośliwych. W PyPI nie ma już MemoryOS 2.0.34, a najnowszym wydaniem jest 2.0.33, przesłane 3 września 2026 r.; przez siedem tygodni od tego czasu nie pojawiło się żadne kolejne wydanie w PyPI.

To, co się nie zmieniło, to publiczny przekaz projektu. W repozytorium nie ma żadnych biuletynów bezpieczeństwa, zgłoszenie na GitHubie z godz. 04:17 w dniu incydentu wciąż pozostaje otwarte i bez odpowiedzi, a żadna z omówionych tu relacji nie cytuje oświadczenia MemTensor ani OpenClaw. Żaden ze złośliwych pakietów nie miał poświadczenia pochodzenia, co – jak zauważa SafeDep – usuwało jedyny sygnał wskazujący, że artefakty zbudowano z nieoczekiwanego commita.

Odpowiedź, która faktycznie istnieje, dotyczy strony wykrywania: StepSecurity dodało domeny command-and-control skyleen[.]fr do swojej globalnej listy blokowanych, a oba pakiety są śledzone w OSV jako MAL-2026-16476 i MAL-2026-16475.

Jeśli zainstalowano podatną wersję

Wytyczne Socket są najsurowsze i najprostsze: jeśli załadowano lub zaimportowano jakąkolwiek wymienioną wersję, uznaj ten host za skompromitowany, w tym runnery CI i kontenery, które tylko uruchamiały testy. Konkretne kroki, co do których cztery firmy są zgodne:

• Usuń pakiet i przypnij do czystej wersji — npm 0.1.20, PyPI 2.0.33. StepSecurity ostrzega, że jego analiza nie ustaliła czystej linii bazowej PyPI, podczas gdy SafeDep i SC Media obydwa wskazują 2.0.33 jako ostatnie dobre wydanie.

• Poszukaj wiersza poleceń procesu, ponieważ plik wykonywalny może sam siebie usunąć: sckit stage0 --config64, oraz zmiennej środowiskowej SCKIT_EVENT_TEXT.

• Usuń katalogi stanu ~/.openclaw/.cache/runtime i ~/.memos/.cache/runtime oraz sprawdź repozytoria pod kątem nieoczekiwanego runtime-update.yml przepływu pracy lub .sckit/ katalogów.

Zrotuj wszystkie poświadczenia osiągalne z katalogu domowego i środowiska procesu, z czystej maszyny: npm, PyPI, GitHub, GitLab, AWS, Vault, SSH, Hugging Face, Slack, Stripe i SendGrid oraz wszelkie wartości .env. Tokeny rejestru i kontroli źródła idą pierwsze.

• Sprawdź wydania własnych pakietów, na wypadek gdyby skradziony token publikowania został użyty do opublikowania wersji, które nie zostały przez Ciebie napisane.

• Zablokuj skyleen[.]fr oraz jej subdomeny i odczytaj logi ruchu wychodzącego od 23 września.

• Wszelkie polecenia lub wklejone sekrety, które przeszły przez wtyczkę, gdy była aktywna, należy traktować jako ujawnione. To jest ta część incydentu, która dotyczy konkretnie pamięci agenta: implant nie musiał skrobać transkryptu, ponieważ transkrypt był mu przekazywany przy każdym przywołaniu.