Релиз LiteLLM собрали из подставного репозитория с похитителем учётных данных

Релиз LiteLLM собрали из подставного репозитория с похитителем учётных данных

В релизе LiteLLM 1.107.0 обнаружены файлы запуска Python, которые собирают облачные учётные данные, закрытые ключи, данные браузеров и файлы авторизации инструментов для разработки с искусственным интеллектом. Активация происходит при обычном старте интерпретатора, и приложению не нужно импортировать сам LiteLLM. Те же файлы найдены в опубликованном контейнерном образе. Записи о происхождении этой сборки называют владельца исходников, чьё имя отличается от имени проекта одной чертой.

Описание

Затронуты семь пакетов wheel (собранных пакетов Python для установки через менеджер пакетов) под macOS, Linux и Windows. Статический анализ подтверждает в них похититель учётных данных (инфостилер) и загрузчик, способный исполнять присланный по сети код Python. Три файла из ревизии, которую записала контейнерная сборка, совпадают с файлами в пакете wheel побайтово. Все они лежат вне основного каталога библиотеки, а установщик помещает их в каталог библиотеки Python того окружения, куда ставится пакет. В конфигурации, приложенной к тегу релиза, добавленная настройка упаковки отсутствует.

Пакет опубликовали 21 октября 2026 года в 11:39:51 UTC, оповещения об угрозе появились в 11:46:30 UTC. {По данным сканера Socket и отчёта Upwind}, LiteLLM скачивают около 23 миллионов раз в неделю, поэтому заражённая установка оказывается рядом с ключами провайдеров моделей, облачными учётными записями и строками подключения к базам данных. Проверка реестра около 13:14 UTC показала, что плавающие теги latest, main-latest и main-stable указывали на тот же образ, что и тег 1.107.0, так что развёртывание по плавающему тегу могло получить затронутый выпуск без явного выбора версии.

Сведения о происхождении контейнерного образа для Linux amd64 называют приватный процесс сборки проекта и его ревизию, а среди входных параметров запуска указан владелец исходников с дефисом в имени. Для предыдущего выпуска 1.106.2 те же записи называют обычного владельца, без дефиса. Сборка по этой записи началась 21 октября 2026 года в 10:51:23 UTC и закончилась в 11:06:31 UTC. Примерно за час до старта в конфигурацию сборки добавили каталог с файлами запуска, а за пять минут до старта - строку, копирующую этот каталог в сборочные стадии контейнеров бэкенда, шлюза и миграций.

Один из файлов запуска содержит единственную строку с импортом модуля. Второй носит имя sitecustomize: интерпретатор Python обрабатывает файлы такого рода при инициализации, до кода приложения. Оба хранят сжатый исходник, закодированный в Base64; после декодирования получились две почти одинаковые реализации похитителя объёмом около 61 килобайта каждая. Сбор идёт в отдельном потоке, повторный сбор в том же окружении подавляется переменной окружения, а после успешной отправки во временном каталоге появляется файл-маркер. Короткоживущий интерпретатор может завершиться раньше потока, и тогда маркера не будет; отсутствие маркера не говорит о том, что сбора не было, поскольку помешать ему могут неудачная отправка, очистка временного каталога или замена контейнера.

Декодированный код включает 16 модулей сбора, и каждый работает под собственным обработчиком ошибок, поэтому отказ одной цели не останавливает остальные. Охват шире ключей провайдеров моделей: облачные платформы, оркестраторы контейнеров, реестры, системы непрерывной интеграции, ключи SSH и GPG, учётные данные менеджеров пакетов, файлы авторизации Codex, Claude, Gemini, Cursor и ещё ряда инструментов, базы браузеров Chromium и Firefox, история команд, переменные окружения процессов. Отдельный модуль нацелен на развёртывания LiteLLM с настроенным подключением к базе данных: дочерняя программа обращается к таблицам с сохранёнными учётными данными и параметрами моделей прокси. Интерес к этим таблицам подтверждён, а успешный доступ к конкретному развёртыванию и расшифровка всех полученных значений - нет. У артефакта для macOS есть ограничения: часть модулей обращается к файлам Linux и на обычной установке не работает, восстановить пароли Chromium в открытом виде не удаётся, хотя базы браузера всё равно копируются.

Второй файл запуска порождает отдельный процесс, который опрашивает управляющий файл в публичном репозитории на GitHub. Если в файле появляется подходящий домен, процесс скачивает с него код Python и исполняет полученный текст без проверки подписи или контрольной суммы. После неудачного цикла пауза составляет 3600 секунд. 21 октября 2026 года в 13:01:44 UTC управляющий файл отдавался с пустым телом, и до загрузки дело не дошло; это не отключает первый механизм сбора и не мешает позже указать другой домен.

Результаты сбора шифруются случайным ключом AES-256-CBC, ключ оборачивается встроенным открытым ключом RSA-4096 по схеме OAEP, а всё вместе упаковывается в gzip-архив из трёх файлов. Архив уходит на домен, созвучный домену проекта, по адресу, оформленному как проверка работоспособности, и в теле запроса лежат зашифрованные результаты. Отправка повторяется до четырёх раз с ожиданием ответа 120 секунд. Этот адрес служит только приёмником: код смотрит на статус ответа и не исполняет его тело.

Что осталось за пределами анализа

Не установлено, как именно разрешили переопределение владельца исходников, был ли скомпрометирован аккаунт или токен и тот ли процесс загрузил пакеты wheel в PyPI. Публичный адрес запуска сборки отдавал 404, приватные журналы заданий остались недоступны. Сведения о происхождении фиксируют входные данные сборки, но не подтверждают их доверенность и не заменяют независимую подпись. Затронутыми также названы образы базы данных и запуска без root в реестре GHCR и образ в Docker Hub, хотя содержимое этих сборок независимо не извлекали. Имя sitecustomize само по себе ничего не доказывает: такой файл бывает легитимным, а пустой управляющий файл или отсутствие маркера не исключают работу первого механизма сбора.

Индикаторы компрометации

Комментарии: 0