Один червь одновременно захватил npm и PyPI
Одна и та же вредоносная программа оказалась сразу по обе стороны языковой границы. 23 сентября в npm и PyPI появились заражённые релизы пакетов MemTensor, внутри которых скрывался кроссплатформенный Go-червь sckit. Команда Aikido обнаружила кампанию и назвала её supplychain.local по имени модуля в бинарнике. До атаки оба пакета долго публиковали обычные версии.
В npm пострадал плагин @memtensor/memos-cloud-openclaw-plugin версий 0.1.21, 0.1.23 и 0.1.25, а в PyPI вредоносный код попал в MemoryOS 2.0.34. Между заражёнными npm-релизами выходили чистые 0.1.22 и 0.1.24. На момент обнаружения вредоносные сборки были последними версиями, поэтому стандартная команда установки могла подтянуть их без явного выбора номера.
Главная особенность атаки скрывалась в моменте запуска. sckit не полагался на preinstall или postinstall и не активировался во время установки. В npm-плагине бинарник стартовал при запуске OpenClaw и обращении к памяти, а в MemoryOS запуск происходил при импорте Python-библиотеки. Поэтому параметр --ignore-scripts не блокировал вредонос, а проверка одних install-хуков могла его пропустить.
После старта sckit просматривал домашний каталог и окружение процессов в поисках секретов. Среди целей были токены npm, PyPI, GitHub и GitLab, ключи AWS и SSH, а также учётные данные HashiCorp Vault, Hugging Face, Slack, Stripe и SendGrid. Доступ к таким данным позволял атакующему переходить от одной заражённой машины к репозиториям, пакетам и облачной инфраструктуре.
SafeDep восстановила цепочку через GitHub Actions самого MemTensor. В рабочие процессы добавляли код, который перехватывал NPM_TOKEN и PYPI_API_TOKEN прямо перед публикацией релиза. Для npm использовали короткоживущие ветки, которые несколько раз создавали и удаляли, а для PyPI подготовили неподписанные коммиты вне основной ветки. Как злоумышленник получил право записи, пока не подтверждено.
Полученные ключи превращали заражённую машину или CI-среду в новую точку распространения. Внутри sckit нашли команды для npm publish, npm version patch и загрузки в PyPI через twine, а также шаблон GitHub Actions, способный запускать имплант после каждого push. Вредонос мог публиковать новые версии через украденные учётные данные и переносить заражение между двумя экосистемами.
Механизм напоминает прежние атаки на цепочки поставок npm, где украденные токены разработчиков использовали для публикации новых заражённых версий. Летом Shai-Hulud уже распространялся через сотни npm-пакетов и крал секреты из окружения разработчиков. supplychain.local расширил подход на PyPI и подготовил бинарники сразу для Windows, Linux и macOS на архитектурах x64 и ARM64.
Подтверждённый масштаб пока ограничен двумя пакетами MemTensor. Aikido не нашла публичных репозиториев, куда sckit успел бы внедрить подготовленный GitHub Actions workflow или вспомогательные JavaScript и Python-загрузчики. Возможность самораспространения присутствует в коде, но доказательств массовой цепной инфекции на момент анализа не было. Новые заражённые пакеты также не подтверждены.
По состоянию на 28 сентября заражённые npm-релизы 0.1.21, 0.1.23 и 0.1.25 удалены, а тег latest указывает на чистую 0.1.24. PyPI снова показывает MemoryOS 2.0.33 как последнюю доступную версию. SafeDep советует пользователям заражённых сборок удалить пакет, завершить процессы sckit, проверить репозитории на неожиданные workflow и сменить все ключи и токены, доступные заражённой системе.