Взлом LiteLLM на PyPI: как хакеры превратили ИИ-библиотеку в кражу паролей

Хакерская группа TeamPCP опубликовала вредоносные версии LiteLLM на PyPI. Трёхступенчатый стилер крал credential'ы и распространялся по Kubernetes-кластерам. Разбираем цепочку атаки и способы защиты.

Взлом LiteLLM на PyPI: как хакеры превратили ИИ-библиотеку в кражу паролей
Issue #24512 в репозитории BerriAI/litellm. Источник: GitHub

24 марта 2026 года хакерская группа TeamPCP опубликовала на PyPI две вредоносные версии LiteLLM — популярной Python-библиотеки, через которую тысячи проектов подключаются к языковым моделям OpenAI, Anthropic, Google и других провайдеров. Версии 1.82.7 и 1.82.8 содержали трёхступенчатый стилер, который крал SSH-ключи, облачные credential'ы, токены Kubernetes — и разворачивался по кластеру.

Пакеты провисели на PyPI около трёх часов. При этом LiteLLM скачивают порядка 3,4 миллиона раз в день.

Статья Snyk о supply chain атаке на LiteLLM через PyPI
Разбор инцидента от Snyk Security. Источник: snyk.io

Цепочка атаки: пять дней от Trivy до LiteLLM

Взлом LiteLLM не был единичным событием. Он стал финальным звеном в пятидневной кампании, которая началась с компрометации совсем другого инструмента — сканера безопасности Trivy от Aqua Security.

19 марта — атакующие получили доступ к учётным данным Trivy на GitHub. Они выпустили вредоносный релиз v0.69.4, подменили теги в GitHub Actions trivy-action и setup-trivy, а внедрённый код сливал содержимое памяти CI-раннеров и собирал credential'ы. Данные шифровались и отправлялись на домен-двойник scan.aquasecurtiy[.]org (с опечаткой в названии).

20–22 марта — с украденными npm-токенами группа запустила червя CanisterWorm, заразив 28 пакетов в области @EmilGroup, 16 в @opengov и ещё несколько. Червь действовал автоматически: находил токен, определял доступные пакеты, обновлял patch-версию и публиковал заражённую копию. На тот же период пришлась дефейс-атака на внутреннюю GitHub-организацию Aqua Security — 44 репозитория были переименованы с префиксом tpcp-docs-.

23 марта — заражены GitHub Actions Checkmarx KICS, расширения OpenVSX. Зарегистрирован домен models.litellm.cloud — за день до атаки на LiteLLM.

24 марта — CI/CD-пайплайн LiteLLM запустил Trivy как часть сборки. Заражённый Trivy выкрал токен PYPI_PUBLISH из окружения GitHub Actions. С этим токеном атакующие опубликовали версии 1.82.7 (10:39 UTC) и 1.82.8 (10:52 UTC).

Диаграмма кампании TeamPCP: от Trivy до LiteLLM
Визуализация кампании TeamPCP. Источник: Wiz Threat Center

Два механизма заражения

Две вредоносные версии использовали разные методы запуска:

Версия 1.82.7 — вредоносный код закодирован в base64 и вшит в файл litellm/proxy/proxy_server.py. Он срабатывал при импорте модуля litellm.proxy, то есть при запуске LiteLLM в режиме прокси-сервера.

Версия 1.82.8 — добавлен файл litellm_init.pth в site-packages/. Формат .pth — особенность Python: такие файлы исполняются при каждом запуске интерпретатора. Не нужен ни import, ни запуск приложения. Достаточно pip install или даже python -c "" — и код уже выполнен.

Именно версия 1.82.8 привлекла первое внимание. Каллум Макмахон из FutureSearch тестировал MCP-плагин для Cursor, который тянул LiteLLM как зависимость. Машина зависла от нехватки памяти: .pth-файл порождал дочерний процесс Python, который снова запускал .pth, создавая fork-бомбу. Случайный побочный эффект вредоносного кода обнаружил саму атаку.

Что делал вредоносный код

Пейлоуд работал в три этапа.

Этап 1 — сбор данных. Скрипт собирал всё, до чего мог дотянуться: переменные окружения, SSH-ключи, .env-файлы, git-credential'ы, историю командной строки, конфиги CI/CD (Jenkins, Travis CI, Terraform), хэши паролей из /etc/shadow. Отдельно обрабатывались облачные credential'ы AWS, GCP и Azure, включая прямые запросы к IMDS (с полной реализацией подписи IMDSv2). Kubernetes-секреты, Docker-конфиги, Slack- и Discord-вебхуки, криптовалютные кошельки Bitcoin, Ethereum, Solana и Monero — скрипт брал всё подряд.

Этап 2 — шифрование и эксфильтрация. Собранные данные шифровались AES-256, сеансовый ключ — RSA-4096 с вшитым публичным ключом. Пакет отправлялся на models.litellm[.]cloud (домен, зарегистрированный за день до атаки). RSA-ключ оказался идентичным тому, что использовался в атаках на Trivy и KICS, — самая сильная техническая привязка ко всей кампании.

Этап 3 — закрепление и распространение. На диске появлялся бэкдор ~/.config/sysmon/sysmon.py с systemd-сервисом sysmon.service (описание — «System Telemetry Service»). Каждые 5 минут он обращался к checkmarx[.]zone/raw за новыми командами. Если обнаруживался токен сервис-аккаунта Kubernetes, скрипт читал секреты во всех namespace'ах и разворачивал привилегированные поды node-setup-* на каждом узле кластера, монтируя корневую файловую систему хоста.

Для иранских систем (определялись по таймзоне и локали) логика была другой: вместо бэкдора запускался контейнер kamikaze, который удалял файловую систему хоста и перезагружал ноду.

Подавление раскрытия

Когда сообщество начало сообщать об инциденте в GitHub issue #24512, атакующие ответили быстро: 88 бот-комментариев от 73 взломанных аккаунтов за 102 секунды. 76% аккаунтов пересекались с ботнетом, использованным при подавлении раскрытия Trivy. Через скомпрометированный аккаунт мейнтейнера issue был закрыт как «not planned».

Сообщество открыло параллельный тикет #24518 и продолжило обсуждение на Hacker News, где тред набрал 324 очка. К 15:09 UTC мейнтейнеры LiteLLM подтвердили ротацию всех ключей — GitHub, Docker и PyPI.

Кто стоит за атакой

TeamPCP (они же PCPcat, Persy_PCP, ShellForce, DeadCatx3) — группа, активная как минимум с декабря 2025 года. Ведут Telegram-каналы @Persy_PCP и @teampcp, встраивают метку «TeamPCP Cloud stealer» в пейлоуды.

Атака на LiteLLM — девятая фаза их кампании. Общие маркеры: один и тот же RSA-ключ, одинаковое имя архива tpcp.tar.gz, GitHub-репозитории с префиксом tpcp-docs- для промежуточного хранения данных.

В арсенале группы нашёлся hackerbot-claw — ИИ-агент на базе openclaw, который автоматизировал выбор целей. По данным исследователей Aikido, это один из первых задокументированных случаев применения ИИ-агента в supply chain атаке.

Группа также применяла CanisterWorm с управлением через Internet Computer Protocol (ICP) — децентрализованный блокчейн, на котором невозможна блокировка со стороны регистраторов доменов и хостеров.

Кого затронуло

Среди проектов, которые экстренно обновили зависимости 24 марта: DSPy, MLflow, OpenHands, CrewAI, langwatch, Arize Phoenix, strands-agents. Aider оказался в безопасности — там была закреплена версия litellm==1.82.3.

Официальный Docker-образ прокси LiteLLM не пострадал: он использует requirements.txt с закреплёнными зависимостями и не тянет пакеты с PyPI напрямую.

Как проверить, затронуты ли вы

Если в ваших проектах есть LiteLLM, проверьте:

  1. Версию: pip show litellm | grep Version. Если 1.82.7 или 1.82.8 — система скомпрометирована.
  2. Файл .pth: поищите litellm_init.pth в site-packages/.
  3. Бэкдор: проверьте наличие ~/.config/sysmon/sysmon.py и ~/.config/systemd/user/sysmon.service.
  4. Kubernetes: kubectl get pods -A | grep node-setup- — поды с таким именем создавал вредоносный код.
  5. Сетевые индикаторы: исходящий трафик на models.litellm[.]cloud и checkmarx[.]zone.

Если версия 1.82.7 или 1.82.8 была установлена хоть на минуту — это не просто обновление пакета. Нужна полная ротация credential'ов: SSH-ключи, облачные токены, API-ключи, Docker-registry, Kubernetes-секреты. Код выполнялся в момент установки, до запуска приложения.

Уроки: что стоит изменить после этой атаки

Закрепление версий работает, но не спасает от всего. Aider уцелел, потому что использовал ==1.82.3. Официальный Docker-образ LiteLLM тоже не пострадал, но по другой причине: изолированный путь сборки. При этом pip install --require-hashes здесь бы не помог — пакет был подписан настоящими credential'ами мейнтейнера.

CI/CD-инструменты оказались удобной мишенью. Trivy, KICS, GitHub Actions по дизайну имеют доступ к секретам. Компрометация одного сканера безопасности открыла дорогу к десяткам других проектов.

Механизм .pth-файлов в Python до сих пор не закрыт. Мейнтейнеры CPython знают о проблеме (issue #113659), но патча нет. Любой пакет может положить исполняемый .pth-файл, и он запустится при старте интерпретатора — без import, без явного вызова.

Отдельный риск — централизованные LLM-шлюзы. LiteLLM часто стоит как единый прокси ко всем LLM-провайдерам, храня API-ключи OpenAI, Anthropic, Google в одном месте. Взлом такого узла даёт доступ сразу ко всей ИИ-инфраструктуре компании.

Три часа на PyPI — мало по меркам прошлых supply chain атак. Случайная fork-бомба и активное сообщество спасли ситуацию. Но при 3,4 миллиона скачиваний в день даже за три часа могли пострадать тысячи установок.


По состоянию на 26 марта 2026 года. Источники: Datadog Security Labs, Snyk, LiteLLM official blog, Simon Willison, Wiz Threat Center.

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

Telegram-канал @toolarium