LiteLLM 1.107.0: в официальный релиз встроили стилер и бэкдор

· ·

LiteLLM 1.107.0: в официальный релиз встроили стилер и бэкдор

PrimeCoder · 2026 · формат: news

Что произошло, почему это важно и что взять в работу.

Чистый код в GitHub не гарантирует чистый пакет — командам пора фиксировать версии и хеши, ставить карантинное зеркало PyPI и убирать долгоживущие ключи из CI.

Связанные услуги: каталог, AI Boost Team, стать клиентом.

Худший релиз в году для ИИ-инфраструктуры выглядел буднично: тег, подпись, статус официального пакета. Всё на месте. Внутри, по разбору УЦСБ, ехали инфостилер privcollect и бэкдор с удалённым выполнением кода. LiteLLM 1.107.0 несколько часов работал как единый API не только к моделям, но и к секретам того, кто его запустил.

Масштаб ставок понятен из двух чисел: около 90 млн скачиваний в месяц и больше 60 тыс. звёзд на GitHub. Это не нишевая библиотека, которую обновляют по пятницам. Это слой, через который приложение ходит к моделям разных провайдеров, а значит, сидит рядом с ключами и деньгами.

Что произошло и в какие часы

21 октября 2026 года конвейер публикации был скомпрометирован. Заражённые артефакты лежали в трёх местах с разными окнами экспозиции: в PyPI с 14:39 до 16:23 МСК, в Docker Hub с 14:46 до 17:20, в GHCR с 14:46 до 16:51. Затронуты все семь wheel-пакетов, а также образы litellm, litellm-database и litellm-non_root. Теги v1.107.0, latest, main-latest и main-stable указывали на заражённое.

Отдельно стоит запомнить оговорку про приватный реестр: он не затронут, enterprise-клиенты, которые тянут пакеты оттуда, инцидент не задели. Это важный сигнал для тех, кто выбирает схему поставки. Разница между «пакет из интернета» и «пакет из своего контура» здесь отработала как страховка.

Сборку увели в репозиторий с одним лишним дефисом

Код в официальном репозитории не менялся. Тег v1.107.0 там чистый. Атакующие вмешались в процесс публикации и перенаправили сборку в похожий репозиторий Berri-AI/litellm, который отличается от настоящего BerriAI/litellm одним дефисом. Пакет собрали, подписали и выпустили через штатный конвейер.

Вредоносный пакет собрали и подписали, не трогая официальный код. То есть чистый код на GitHub еще не гарантирует чистый пакет.

Входная точка появилась задолго до релиза. Мастер-ключ LiteLLM Agent Platform утёк в публичный репозиторий LiteLLM-Labs/lite-harness 27 мая 2026 года. Коммит с конфигурационным файлом переписали, а ключ не отозвали. 10 октября его использовали: получили GitHub CLI OAuth-токен владельца организации, затем токены двух мейнтейнеров, обошли защиту ветки. Проект к тому моменту временно ослабил процедуру согласования релизов. Этим и воспользовались.

Читается как учебник по тому, чего не делать с секретами в CI. Переписанная история коммита не отзывает ключ. Токен, который никто не сжёг, живёт до момента, когда им воспользуются, и никто не узнает, что он «светился».

Почему это срабатывает даже там, где есть сканеры

В пакеты добавили три файла: cook.pth, cook.py и sitecustomize.py. Они используют штатные механизмы запуска Python. cook.pth импортировал cook.py, который поднимал стилер privcollect. sitecustomize.py работал на Linux и macOS и запускал фоновый загрузчик для удалённого выполнения кода.

Дальше главное: вредонос активировался при любом запуске Python в заражённом окружении, включая запуск pip. То есть даже проверка «а какая версия у нас стоит» через pip show могла стоить ключей. Загрузчик раз в час обращался к GitHub-репозиторию letters9813/pythonclient-test, читал domain.txt с адресом управляющего сервера и скачивал скрипт с /codepy. Никакой экзотики, всё на инфраструктуре, которой разработчики доверяют по умолчанию.

Что уходит на сторону и что с этим делают

Стилер собирал облачные ключи AWS, Azure и Google Cloud, доступы к Kubernetes и Docker, токены GitHub, npm и PyPI, SSH-, GPG- и TLS-ключи, файлы .env, данные браузеров и токены AI-инструментов, включая Cursor и GitHub Copilot. Отправка шла на litellm.dev/healthcheck. Через 4,5 часа после утечки ключи AWS уже проверяли через sts:GetCallerIdentity, а затем смотрели модели Bedrock. Похоже на LLMjacking: чужой бюджет тратится на ваши счета за токены.

ФактЧто это значит
Официальный релиз, подпись на местеПодпись подтверждает, кто собрал пакет, а не что внутри. Проверять надо конвейер, а не только артефакт
Сборка ушла в Berri-AI/litellmОпечатка в имени репозитория опаснее уязвимости: код чистый, а пакет нет
Активация при любом старте PythonКарантин «на посмотреть» не работает. Запуск pip в заражённом окружении уже утечка
Ключ утёк 27 мая, не отозван, применён 10 октябряПять месяцев тишины между утечкой и атакой. Ротация секретов важнее их сложности
Внутренние зеркала и кешиЗаражённая версия продолжает жить в контуре после того, как её удалили из PyPI

Это второй заход за год, и он другой

24 марта 2026 года в PyPI уже выходили вредоносные 1.82.7 и 1.82.8. Тогда полезная нагрузка сидела в proxy_server.py и срабатывала при импорте, а в 1.82.8 появился litellm_init.pth с запуском при каждом старте Python. Пакеты были доступны от 40 минут до 2,5 часов: LiteLLM говорил примерно о 40 минутах, PyPI о 2 часах 32 минутах. Данные уходили на models.litellm.cloud, а вредонос пытался закрепиться в Kubernetes через привилегированные поды. Чистой тогда считалась 1.82.6, чистая 1.83.0 вышла 30 марта. Инцидент связывают с группировкой TeamPCP и скомпрометированным GitHub Action aquasecurity/trivy-action, но связь подтверждена не полностью.

Разница между мартом и октябрём принципиальная. В марте правили код пакета, и это ловилось глазами при разборе. В октябре не тронули ни строчки кода, а переписали процедуру выпуска. Порог входа ниже: нужен не доступ к репозиторию, а один живой токен мейнтейнера.

Что делать, если 1.107.0 у вас запускалась

  1. Проверить следы: pip show litellm, lock-файлы, SBOM, локальные кеши, внутренние зеркала, образы и дайджесты, CI-раннеры и машины разработчиков.
  2. Не запускать Python и pip в этом окружении. Удалить cook.pth, cook.py, sitecustomize.py и связанные файлы __pycache__, остановить процесс, держащий /tmp/remote_code_loader.lock, пересобрать окружение или образ с нуля на версии 1.106.2.
  3. Считать данные скомпрометированными, если был исходящий интернет. С чистого хоста отозвать облачные ключи и роли, секреты Kubernetes и Docker, токены GitHub, npm и PyPI, SSH-, GPG- и TLS-ключи, .env, ключи провайдеров ИИ, master и virtual keys LiteLLM, пароль DATABASE_URL.
  4. Поискать маркеры: обращения к litellm.dev и letters9813/pythonclient-test, пути /codepy, переменную PRIVCOLLECT_ACTIVE=1, процесс с рабочим каталогом /. Вычистить затронутые артефакты из зеркал, реестров и кешей.

Вердикт

Покупать «безопасный open source» по звёздам на GitHub больше нельзя. Три правила, которые дешевле любого инцидента: фиксируйте LiteLLM и зависимости на конкретных версиях и хешах, не тяните latest в прод. Держите внутреннее зеркало с карантином, проверяйте подписи, provenance и SBOM. Уберите долгоживущие облачные ключи из CI и раннеров, замените короткоживущими токенами с минимальными правами, включите сканирование секретов с автоотзывом и фильтрацию исходящего трафика.

И самое неприятное. Чистый код в официальном репозитории теперь ничего не доказывает. Доказывает только воспроизводимая сборка, которую вы контролируете сами.

Читайте также