Установить гем достаточно, чтобы выполнить чужой код, - отдельный установочный скрипт для этого не нужен. RubyGems запускает сборочные скрипты нативных расширений во время установки, а плагины - в конце команды и при каждом следующем обращении к gem. Даже чтение списка или проверка версии запускает плагин. Четыре гема, опубликованные в 2013-2015 годах, до сих пор доступны для установки и отправляют данные на сторонний сервер.
Описание
Похожую историю уже прошел npm. В кампании Miasma злоумышленники перенесли точку запуска из манифеста пакета в сборочный файл нативных модулей. Инструмент сборки выполняет его автоматически при установке. Проверки, которые следили только за установочными хуками, это пропустили. Ответом стала следующая мажорная версия npm: она сделала установочные скрипты зависимостей опциональными, включая нативные сборки. RubyGems пока идет прежним курсом: сборки расширений и плагины работают по умолчанию. Стабильные RubyGems и Bundler 4.0.x не дают отключить ни то, ни другое. В кампании SleeperGem вредоносные версии гемов выходили с заброшенных аккаунтов сопровождающих.
На практике, по данным Aikido, при проверке собственных правил обнаружения нашлись четыре гема, которые выполняют код при установке. Они появились в 2013-2015 годах и выглядят как исследовательские пробы. При этом каждый отправляет данные с машины установщика: имя пользователя, скрытый снимок экрана macOS или простой сигнал на удаленный сервер. На 4 ноября 2026 года все четыре по-прежнему доступны на RubyGems. Пути выполнения расширений и плагинов компания передала команде безопасности RubyGems 27 октября. Сами гемы - 30 октября. В общей ленте подписчики видят такие гемы как инцидент вредоносного ПО. Имена находок:
- xmastree
- ancient-city-ruby
- hacky
- et_phone_home
Оба механизма работают по-разному. Для нативного расширения хватает одного файла. В манифесте гем объявляет сборочный скрипт extconf.rb, и RubyGems исполняет его во время установки, а затем запускает сборку. Любой Ruby-код в этом файле получает доступ к файлам и переменным окружения разработчика еще до старта приложения. Внешне это обычная конфигурация сборки, и легитимные гемы используют такой скрипт постоянно. Отдельного раздела со скриптами в манифесте нет, поэтому при беглом просмотре файл не выделяется. Проверка охватила примерно тысячу самых скачиваемых гемов. Из них 74 объявляют шаги сборки расширений.
С плагинами тише. Файл rubygems_plugin.rb в каталоге библиотеки превращает гем в плагин без отдельного объявления. Такой файл несут два гема из той же выборки. В конце установки загрузчик плагина срабатывает сразу, если другая версия гема не установлена. Дальше он подхватывается при каждой команде gem, включая чтение списка, поиск и проверку версии. Ошибку RubyGems покажет предупреждением и продолжит выполнение. Сбой плагина легко пропустить. Плагин работает, пока гем остается на машине.
Поэтому выключить оба поведения в стабильной ветке нельзя. Настройки отказа появились только в предварительной версии 4.1.0.beta3. И там сборки расширений и плагины остаются включенными по умолчанию: администратор должен отключить их сам. В стабильной 4.0.x такие параметры не работают: команда завершается ошибкой. Настройки останавливают код только на этапе установки: когда приложение или тесты загружают гем, его код все равно срабатывает. Поэтому защита закрывает установочные шаги, а не работу с уже собранным бандлом. В CI отключать сборку расширений стоит только в задаче, которая не загружает приложение, иначе тесты не увидят гемы без собранных расширений. Исключение - бандл, где у каждого гема есть готовая платформенная сборка.
Пока что RubyGems не меняет настройки по умолчанию. Четыре находки на 4 ноября 2026 года по-прежнему доступны для установки.