Релиз LiteLLM 1.107.0 на PyPI содержал похититель учётных данных

Релиз LiteLLM 1.107.0 на PyPI содержал похититель учётных данных

21 октября 2026 года в каталоге PyPI появилась библиотека LiteLLM версии 1.107.0, и все семь её сборок wheel (собранных пакетов Python для установки через менеджер пакетов) несли два вредоносных компонента. Те же файлы обнаружились в официальных Docker-образах LiteLLM, включая теги latest, main-latest и main-stable, которые указывали на заражённую сборку около трёх часов. LiteLLM объединяет более 100 поставщиков языковых моделей за одним интерфейсом, совместимым с OpenAI, и применяется на рабочих машинах разработчиков, в конвейерах сборки и на производственных шлюзах с ключами доступа к моделям.

Описание

К 13:23 по UTC того же дня релиз сняли с PyPI, а заражённые образы удалили из обоих реестров. Это второе за год попадание LiteLLM в PyPI с вредоносным кодом: в марте пострадали версии 1.82.7 и 1.82.8.

Проверка содержимого подтвердила, что в каждой из семи сборок wheel лежали три файла, которых нет ни в одном предыдущем выпуске и нет в релиз-кандидатах 1.107.0. Один из них, файл .pth с директивой импорта, заставляет интерпретатор Python выполнить код при каждом запуске. Второй представляет собой сжатый скрипт похитителя, третий - модуль sitecustomize, который интерпретатор импортирует автоматически. Установка помещает все три в корень каталога установленных пакетов, поэтому импортировать саму библиотеку не требуется. По данным BerriAI, разработчик библиотеки подтвердил удаление заражённых образов из обоих реестров и сообщил об отзыве всех задействованных токенов.

Сборка шла не из основного репозитория. Метаданные происхождения Docker-образов называют источником репозиторий Berri-AI с дефисом в названии, отдельный от настоящей организации BerriAI. С 08:56 до 10:46 по UTC 21 октября в этот репозиторий добавили десять коммитов. Первые три за две минуты внесли файлы автозапуска, следующие четыре подняли номер версии до 1.107.0. Ещё два уточнили нагрузку и добавили в конфигурацию сборки строку, которая велела инструменту maturin упаковать каталог cook внутрь пакета. Последний коммит, спустя почти час, добавил копирование этого каталога в Dockerfile.

По данным Wiz Research, через 4,5 часа после отправки собранных данных началось использование украденных учётных данных. Между 16:20 и 17:01 по UTC 21 октября с двух адресов проверяли роли AWS, полученные с заражённых узлов сборки и узлов Kubernetes. Каждую пару учётных данных проверяли запросом на подтверждение личности вызывающей стороны, после чего запрашивали список базовых моделей Bedrock, что характерно для перепродажи доступа к моделям. В небольшом числе сред перебирали роли, пользователей и ключи IAM. Два названных адреса - единственное, что связывает эти проверки с октябрьским релизом.

Похититель, называющий себя privcollect, состоит из 16 модулей сбора. Он забирает пароли и файлы cookie браузеров Chrome, Firefox, Edge и Safari, ключи SSH и GPG, файлы облачных учётных данных и метаданные экземпляров AWS, GCP и Azure, конфигурации более 20 инструментов ИИ-разработки и окружение всех доступных процессов. Отдельный модуль обращается к базе данных LiteLLM-прокси и выгружает до 500 записей учётных данных поставщиков и до 500 записей моделей. Собранное шифруется алгоритмом AES-256-CBC, ключ обёрнут открытым ключом RSA-4096, а отправка идёт по незашифрованному HTTP на домен, имитирующий инфраструктуру LiteLLM. В самом коде отмечены признаки генерации языковой моделью: длинные описательные имена переменных, общие блоки перехвата ошибок и объявленный, но нигде не вызываемый модуль.

Второй компонент запускает фоновый процесс на Linux и macOS и раз в час читает управляющий файл в публичном репозитории GitHub (dead drop). Если в файле есть имя домена, процесс скачивает с него скрипт Python и исполняет его. На момент анализа управляющий файл содержал только тестовые значения, а затем его очистили; сам репозиторий и учётная запись удалены. Имя учётной записи при этом можно зарегистрировать заново, и тогда сохранившиеся заражённые хосты снова получили бы канал доставки кода. На Windows ветка загрузчика завершается молча из-за отсутствия нужных системных вызовов, а метка однократного запуска похитителя там не создаётся.

Границы описанной картины важны не меньше самих находок. Архив исходников содержал изменённую конфигурацию сборки, но не содержал каталога с нагрузкой, поэтому проверка одних исходников ничего бы не показала. Предрелизы 1.107.0.dev1-dev3 не проверялись, а последней безопасной версией остаётся 1.106.2. Наличие файлов автозапуска само по себе не доказывает кражу: похититель ставит метку однократного запуска лишь после успешного ответа сервера. Пока сервер не отвечал, сбор данных повторялся при каждом старте интерпретатора, а состав украденного по сетевому трафику установить нельзя - полезная нагрузка зашифрована ключом, которым располагает только отправитель.

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

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