// Искусственный интеллект

Взлом LiteLLM 1.107.0: стилер три часа лежал на PyPI с подписью

Взлом LiteLLM 1.107.0: подписанный вредоносный релиз со стилером и RAT на PyPI и Docker Hub

21 октября 2026 года на PyPI и Docker Hub появился вредоносный LiteLLM 1.107.0: атакующие украли токены GitHub и выпустили релиз через штатный конвейер с подписью. За три часа пакет, по оценке, скачали более 49 000 раз. Внутри были стилер и RAT, которые охотятся за облачными ключами и ключами ИИ-сервисов — то есть ровно за тем, что хранит LLM-прокси.

Коротко

  • Вредоносная версия — LiteLLM 1.107.0 на PyPI и Docker Hub, 21 октября 2026 года, окно около трёх часов, по оценке более 49 000 загрузок.
  • Атакующие украли токены GitHub CLI из логов выставленного в интернет внутреннего инстанса, сняли branch protection и выпустили подписанный релиз из двойника Berri-AI/litellm.
  • Нагрузка — стилер и RAT. Они запускаются при каждом старте Python и забирают облачные, ИИ-, SSH- и GPG-ключи.
  • По данным Wiz, украденные ключи AWS через 4,5 часа использовали для запросов к Amazon Bedrock (LLMjacking).
  • Чистая версия — 1.106.2. Откат не удаляет закрепление: нужны изоляция, ротация с чистой машины и пересборка среды.

Что выложили при взломе LiteLLM 1.107.0

Вредоносная версия одна — LiteLLM 1.107.0. Её опубликовали 21 октября 2026 года сразу в двух каналах: на PyPI и на Docker Hub. LiteLLM — открытый прокси, через который приложения обращаются к разным LLM-провайдерам по единому API. Его ставят и на ноутбуки разработчиков, и в продовые кластеры как шлюз к моделям.

Вредоносные пакеты оставались доступны около трёх часов. В источнике это окно указано общим, без разбивки по PyPI и Docker Hub. За это время их, по оценке, скачали более 49 000 раз. В среднем выходит больше 16 000 загрузок в час — около 270 в минуту.

Эту цифру надо читать аккуратно: она считает загрузки, а не заражённые организации. CI-конвейеры, зеркала и повторные сборки качают один и тот же пакет десятки раз. Но верно и обратное. Каждая автоматическая сборка без закреплённой версии в этом окне подтянула 1.107.0 сама, без участия человека.

Когда атаку обнаружили, версию сняли с PyPI. На Docker Hub заражённые теги и варианты образов удалили или переключили на чистые артефакты. Последний чистый релиз, который называет проект, — 1.106.2.

По заявлению LiteLLM, атака не задела корпоративных клиентов, которые получают пакет из приватного репозитория компании. Это слова самого проекта: как именно проверяли этот канал, публично не расписано.

23 октября инцидент подробно описал SecurityWeek. Технические детали добавили исследователи Wiz и StepSecurity.

Откуда у атакующих взялись токены GitHub CLI?

Атакующие нашли OAuth-токены GitHub CLI во внутреннем инстансе LiteLLM, выставленном в интернет. По данным расследования проекта, токены принадлежали «неожиданной, безобидно названной учётной записи» в этом развёртывании (в оригинале — an unexpected, innocuously named user account).

Как токены туда попали, LiteLLM объясняет гипотезой, а не установленным фактом. По версии мейнтейнеров, Claude Code «в определённых обстоятельствах» вкладывал токены в тело ответа, и такой ответ мог записаться в логи LiteLLM. Какие именно обстоятельства имелись в виду, проект не уточняет.

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

Дальше сработало простое свойство OAuth-токена GitHub CLI: это секрет предъявителя. Кто держит токен, тот действует от имени учётной записи в пределах её прав. Так доступ к логам прокси превратился в доступ к репозиториям и настройкам CI/CD.

В итоге у атакующих оказалось три комплекта учётных данных GitHub CLI, принадлежавших разработчикам. Как злоумышленники попали на выставленный инстанс и как переходили от одного комплекта к другому, проект пока до конца не выяснил.

Отдельный вопрос — сама «безобидно названная» учётная запись. Аккаунт, о котором не знали владельцы, во внутренней системе, открытой наружу, — классическая находка внешнего пентеста. Здесь она обошлась в подписанный релиз.

Практический урок для всех, кто держит у себя LLM-прокси: логи запросов и ответов — такое же хранилище секретов, как vault, только без его защиты. Маскирование токенов и ключей при записи, короткий срок хранения и узкий круг доступа нужны с первого дня, а не после инцидента.

Как из токена получился подписанный релиз

Атакующие захватили не файл в реестре, а сам процесс выпуска, поэтому релиз и вышел подписанным. По описанию LiteLLM, цепочка выглядела так:

  1. с украденными учётными данными сняли защиту веток (branch protection);
  2. влили изменение, которое перенаправило механизм выпуска (releaser) на другой исходный репозиторий;
  3. запустили скомпрометированный GitHub workflow, который брал код уже из репозитория-двойника;
  4. подписали отравленные артефакты и опубликовали их на PyPI и Docker Hub.

Двойник назывался Berri-AI/litellm, настоящий репозиторий — BerriAI/litellm. Разница в одном дефисе. В длинном YAML-файле конвейера её легко пропустить на ревью. Тем более что ревью никто не требовал: защиту веток только что сняли.

Обратите внимание: ни один шаг не потребовал уязвимости в коде LiteLLM или в самом PyPI. Хватило прав трёх разработчиков и того, что изменения в настройках выпуска не проходили через второй, независимый контур контроля.

Отсюда главный вывод для тех, кто полагается на подписи и «официальный источник». Подпись подтверждает, что артефакт выпустил определённый процесс или определённый ключ. О содержимом она ничего не говорит. Если атакующий управляет release workflow, вредоносный пакет подписывается тем же механизмом, что и все предыдущие, и проверка у потребителя пройдёт.

LiteLLM также считает, что вредоносный код, скорее всего, писали с помощью ИИ. Публичный разбор не приводит технических доказательств, так что это мнение пострадавшей стороны, не более.

Сценарий не новый: доверенное имя проекта не спасает, если скомпрометирован сам конвейер. О том, как реестры пакетов превращаются в канал доставки, мы писали и в разборе кампании PhantomRaven в npm.

Что стилер делает на машине с Python

Пакет ставит сразу два инструмента. Стилер разово выгребает секреты, а RAT оставляет атакующему постоянный доступ. Заражены все, кто установил 1.107.0 в окно публикации.

Механизм закрепления простой и неприятный. Полезная нагрузка кладёт три файла в корень site-packages, и они выполняются при каждом старте интерпретатора Python, а не только когда приложение импортирует litellm. Имена и тип файлов в публичных материалах не названы.

Похожий приём хорошо известен: при стандартной инициализации модуль site обрабатывает файлы .pth в site-packages и исполняет строки, начинающиеся с import. Использован ли здесь именно он, источники не уточняют. Итог один: любой вызов python, pip, pytest или entrypoint контейнера снова запускает вредоносный код.

Список того, что собирает стилер, похож на опись рабочей станции ML-инженера:

  • сведения о системе;
  • сохранённые пароли и cookie браузеров, то есть живые сессии;
  • учётные данные инструментов разработчика и переменные окружения;
  • секреты AWS, GCP и Azure;
  • API-ключи ИИ-сервисов: Anthropic, OpenAI, GitHub Copilot и других;
  • приватные SSH-ключи, ключи GPG и история командной оболочки.

Собранное шифруется и уходит на домен, который имитирует имя проекта. Не путайте его с репозиторием Berri-AI/litellm: репозиторий-двойник раздавал вредоносный код, домен-двойник принимает украденное. Адрес мы не приводим — индикаторы компрометации опубликовали LiteLLM и SecurityWeek, брать их нужно оттуда.

По данным StepSecurity, RAT регулярно выходит на сервер управления. Запасной канал у него на GitHub: раз в час он проверяет тайник (dead drop) в GitHub и, по формулировке компании, «выполняет любой Python, который подсунет атакующий». Трафик к GitHub в сети разработчиков — привычный фон, его почти никто не фильтрует. Поэтому блокировка основного сервера управление не обрывает.

Для LLM-прокси такой набор особенно болезнен. LiteLLM по своей роли хранит ключи ко всем провайдерам моделей, которыми пользуется компания, и часто работает с облачными ролями. Стилеру достаётся не случайный ноутбук, а место, где все ключи собраны вместе.

Почему через 4,5 часа это уже был LLMjacking

По наблюдениям Wiz, украденные ключи начали использовать примерно через 4,5 часа после выгрузки. Среди зафиксированных действий — запросы к моделям Amazon Bedrock с похищенными учётными данными AWS. Это типичная картина LLMjacking.

LLMjacking — это обращение к LLM-сервисам в чужом облачном аккаунте с украденными учётными данными. Атакующий получает бесплатные вычисления или перепродаёт доступ, а счёт за токены приходит владельцу аккаунта. Деньги уходят сразу, и первый сигнал скорее появится в биллинге, чем в DLP.

4,5 часа — короче рабочего дня. Если команда узнала о проблеме из новостей на следующее утро, ключи к этому моменту уже работали на атакующих. Если есть подозрение на 1.107.0, проверяйте не только логи доступа, но и потребление Bedrock и аналогичных сервисов в Azure и GCP.

В AWS начните с CloudTrail: вызовы InvokeModel с незнакомых адресов и в регионах, где вы Bedrock не используете, а также запросы на включение доступа к новым моделям. Бюджетные оповещения на ИИ-сервисы стоит настроить заранее — они срабатывают быстрее, чем кто-то откроет счёт в конце месяца.

Что делать, если LiteLLM 1.107.0 могли поставить?

Исходите из того, что любая система, где стоял 1.107.0, скомпрометирована целиком, а не просто «содержит плохой пакет». Откат на 1.106.2 нужен, но сам по себе ничего не лечит: файлы в site-packages переживают pip uninstall.

Мы рекомендуем такой порядок:

  1. Найти, где была версия. Проверьте lock-файлы, requirements без закреплённых версий, логи CI за 21 октября, внутренние зеркала PyPI, хранилища артефактов, кэши pip и собранные образы. Удаление из PyPI не удаляет пакет из ваших кэшей и зеркал, поэтому период риска длиннее трёхчасового окна.
  2. Проверить Docker по digest, а не по тегу. Тег можно переназначить. После переключения на чистый артефакт повторный docker pull скачает чистый образ и ничего не скажет о том, что работало 21 октября. Ищите sha256 в логах реестра, оркестратора и среды выполнения.
  3. Изолировать и сохранить. Отключите подозрительные хосты и CI-раннеры от сети, снимите образ диска или хотя бы каталог site-packages и логи установок. Не запускайте python, pip и тесты «для диагностики»: это снова активирует нагрузку. Осматривайте копию файловой системы.
  4. Ротировать с чистой машины и только после сдерживания. Пока RAT жив, новые секреты уйдут вслед за старыми. Порядок: облачные ключи и временные сессии AWS/GCP/Azure, токены GitHub, ключи LLM-провайдеров, SSH и GPG, браузерные сессии.
  5. Найти следы и пересобрать среду. Ищите нештатные файлы в корне site-packages, обращения к домену-двойнику из IOC проекта, периодические запросы процессов Python к GitHub, нетипичные вызовы Bedrock. Затем пересоберите среду из проверенных источников, а не «чистите» существующую.

Отдельно проверьте свою организацию на GitHub. В журнале аудита ищите отключение branch protection, правки файлов workflow и изменение источников выпуска. Отзовите OAuth-авторизации GitHub CLI у всех, кто работал с заражёнными машинами, и пересмотрите, у кого вообще есть право снимать защиту веток.

Клиентов, которые берут LiteLLM из приватного enterprise-репозитория, атака, по словам проекта, обошла. Но разработчики часто держат рядом открытую версию для локальных экспериментов, так что ноутбуки проверить всё равно нужно.

Из практики. На проектах по аудиту безопасности ML/AI мы раз за разом видим одну картину. LLM-прокси развёрнут «временно». Ради отладки запросы и ответы логируются целиком. Логи лежат там, куда есть доступ у половины команды, а сам инстанс выставлен в интернет, чтобы до него дотягивались внешние агенты.

В таких логах находятся ключи провайдеров, внутренние документы из промптов, иногда токены — ровно то, что случилось у LiteLLM. Проверьте, что пишут ваши прокси, кто читает логи и видна ли админка из интернета.

Закрепляйте версии и хэши зависимостей, требуйте ревью изменений workflow и не давайте одному токену снимать branch protection. Это базовая гигиена DevSecOps, и она рвёт описанную цепочку сразу в двух звеньях.

Если признаки заражения подтвердились, начинайте с реагирования на инцидент, а не с ротации наугад.

Что пока неизвестно и с чем не путать

Часть открытых вопросов прямо влияет на оценку риска:

  • как атакующие попали на выставленный инстанс и как переходили между тремя комплектами учётных данных — проект сам называет это неясным;
  • при каких именно обстоятельствах Claude Code вкладывал токены в ответ — пока это гипотеза LiteLLM без технических подробностей;
  • сколько организаций реально заражено — оценка в 49 000 загрузок на этот вопрос не отвечает;
  • кто атакует — группа, страна или псевдоним не названы;
  • на чём основана оценка, что вредонос писали с помощью ИИ.

Одно можно сказать уже сейчас. ИИ-инструменты разработчика здесь оказались вероятным источником утечки, ИИ-прокси — целью, а облачные LLM — способом монетизации. Модель угроз для AI-инфраструктуры должна учитывать все три роли.

И ещё одно: этот эпизод не связан с историей о компрометации примерно 2500 организаций. У SecurityWeek есть отдельный материал о том, что за ней стоял Trivy, а не LiteLLM. Атака 21 октября самостоятельна: другая точка входа, конкретная версия 1.107.0, конкретное окно. Не смешивайте их в отчётах и тикетах — меры реагирования разные.

Частые вопросы

Какая версия LiteLLM вредоносная и какая безопасная?

Вредоносная — 1.107.0, опубликованная 21 октября 2026 года на PyPI и Docker Hub. Последняя чистая версия, которую называет проект, — 1.106.2.

Сколько времени вредоносный LiteLLM был на PyPI?

Около трёх часов; источник называет это окно общим для PyPI и Docker Hub. За это время пакет и образы скачали, по оценке, более 49 000 раз.

Что ворует вредоносный LiteLLM 1.107.0?

Сведения о системе, пароли и cookie браузеров, переменные окружения, секреты AWS, GCP и Azure, API-ключи Anthropic, OpenAI, GitHub Copilot и других сервисов, SSH- и GPG-ключи, историю командной оболочки. Кроме того, ставится RAT с удалённым выполнением Python.

Достаточно ли удалить LiteLLM 1.107.0, если он уже установлен?

Нет. Нагрузка кладёт три файла в site-packages и запускается при каждом старте Python. Систему нужно изолировать, ротировать все доступные ей секреты с чистой машины и пересобрать среду.

Затронул ли взлом корпоративных клиентов LiteLLM?

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

Что такое LLMjacking?

Это использование украденных облачных учётных данных для обращения к LLM-сервисам в чужом аккаунте, например к Amazon Bedrock. Платит за это владелец аккаунта.

LLM-прокси, агенты и RAG давно хранят больше ключей, чем любой другой сервис в инфраструктуре. Команда SecurityLab.pro проверит, что они логируют, что видно снаружи и как защищён ваш конвейер выпуска, — при пентесте ИИ и LLM-приложений.


← назад в блог