21 октября 2026 года релиз litellm 1.107.0 попал на PyPI из ревизии с похитителем учётных данных и загрузчиком полезной нагрузки. LiteLLM - прокси и комплект разработки, стоящий перед программными интерфейсами поставщиков языковых моделей. Обслуживающие его процессы обычно держат ключи доступа к поставщикам, облачные учётные данные и строки подключения к базам. Правка конфигурации сборки появилась в 09:48 по UTC, публикация на PyPI состоялась в 11:39. Релиз с тех пор помещён в карантин, поэтому автоматическая загрузка через менеджеры пакетов не проходит, а последний незатронутый выпуск на PyPI - 1.106.2.
Описание
Подтверждённая часть картины касается упаковки, а прикладной код LiteLLM не изменён. В конфигурацию сборки добавили одну строку, которая копирует в каталог установленных пакетов Python три служебных файла. Первый - файл с расширением .pth с единственной строкой импорта; интерпретатор исполняет такие строки при каждом старте. Второй - короткая обёртка, распаковывающая встроенный набор модулей сбора объёмом около 61 тысячи байт, третий - модуль sitecustomize, который Python импортирует автоматически. Оба механизма запускаются до приложения, поэтому полезная нагрузка срабатывает при любом обращении к интерпретатору, даже если приложение к LiteLLM не обращается.
Загрузчик полезной нагрузки действует отдельно от модулей сбора. Модуль sitecustomize несёт его в открытом виде и раз в час исполняет ответ, полученный по указателю из публичного репозитория, без проверки подписи. Указатель изменяем, поэтому оператор включает или перенаправляет загрузчик без выпуска нового пакета. Как показало исследование, приложенные к контейнерной сборке сведения о происхождении называют владельцем исходников организацию, которая отличается от законной одним дефисом. Каким образом такую подмену авторизовали, материалы не устанавливают, и официальная метка версии не содержит ни строки в конфигурации, ни каталога с полезной нагрузкой.
Перед отправкой сборщик шифрует результаты алгоритмом AES-256 в режиме сцепления блоков и упаковывает ключ открытым ключом RSA. Затем он отправляет сжатый архив по адресу, замаскированному под проверку состояния; запрос несёт заголовок с токеном и контрольную сумму тела. Повторов не больше четырёх, ожидание ответа - до 120 секунд. В теле запроса лежит зашифрованный результат сбора, а ответ сборщик не исполняет и проверяет только код состояния. Отправка идёт в фоновом потоке, чтобы не задерживать запуск интерпретатора.
Затронуты не только те, кто сознательно выбрал версию 1.107.0: плавающие теги контейнерных образов указывали на вредоносный образ в тот же день. Следовательно, развёртывание, забирающее образ по такому тегу, могло получить его без явного выбора версии. Один из модулей сбора обращается к таблицам, где прокси LiteLLM хранит учётные данные поставщиков и конфигурацию моделей. Поэтому скомпрометированный прокси раскрывает все ключи, которые обслуживает. Остальные модули собирают облачные учётные данные, ключи SSH и GPG, историю командных оболочек, конфигурацию средств разработки с поддержкой моделей и переменные окружения процессов.
Описанные индикаторы не показывают, состоялась ли выгрузка собранных данных. Отметка об успешной отправке появляется только после неё, а проваленная отправка, очистка временного каталога и замена контейнера следа не оставляют. Файл с именем sitecustomize встречается и в легитимных пакетах, поэтому совпадение по имени даёт ложные срабатывания. Список артефактов не отвечает и на вопрос об авторстве: сведения о происхождении называют владельца исходников, но не называют конкретное лицо. Совпадения по контрольным суммам подтверждают установку определённых файлов, однако ничего не говорят об объёме прочитанного ими.