В этом статье мы подробно рассмотрим две недавние атаки на цепочку поставок популярных пакетов PyPI — litellm и telnyx. Также, для разработчиков и сопровождающих проектов на Python, предоставим наши рекомендации о том, как подготовиться и защититься от будущих инцидентов.
Что произошло с LiteLLM и telnyx?
После утечки токена API из‑за взломанной зависимости Trivy, в PyPI были опубликованы релизы пакетов litellm и telnyx, содержащие вредоносное ПО для сбора учётных данных.
19 марта 2026 года злоумышленник, используя скомпрометированные учетные данные, опубликовал вредоносные версии Trivy 0.69.4, а также trivy-action и setup-trivy. Хотя первоначально это событие казалось единичным случаем, оно стало результатом более масштабной многоэтапной атаки на цепочку поставок, начавшейся несколькими неделями ранее.
Вредоносное ПО запускалось при установке, собирая конфиденциальные учётные данные и файлы и проникая в удаленный API. Более подробная информация опубликована в уведомлении о проблемах с безопасностью LiteLLM (PYSEC-2026-2), сообщении в блоге LiteLLM об инциденте, уведомлении по telnyx (PYSEC-2026-3) и уведомлении на сайте telnyx.
Детали атаки на LiteLLM (PYSEC-2026-2)
После утечки API‑токенов из‑за взломанной зависимости Trivy, на PyPI были загружены две новые версии litellm, содержащие автоматически активируемое вредоносное ПО, которое собирает конфиденциальные учетные данные и файлы и осуществляет эксфильтрацию данных на удаленный API.
Вредоносный код запускается при импорте любого модуля из пакета и сканирует файловую систему и переменные среды, собирая всевозможные конфиденциальные данные, включая, помимо прочего, закрытые SSH‑ключи, учетные данные для репозиториев Git и Docker, файлы dotenv, токены учетных записей служб Kubernetes, базы данных и конфигурацию LDAP. Также были украдены многочисленные файлы истории командной оболочки и ключи криптокошельков. Вредоносное ПО активно пытается получить токены доступа к облаку с серверов метаданных и извлечь секреты, хранящиеся в AWS Secrets Manager. Все собранные данные отправляются в домен models.litellm[.]cloud
Кроме того, код включает механизм сохранения данных путем настройки сервисного блока SystemD, замаскированного под «System Telemetry Service», на хосте, на котором он работает, а в среде Kubernetes также путем создания нового пода. Затем скрипт сохранения данных обращается к hxxps://сhеckmarx[.]zonе/raw для получения дальнейших инструкций.
Всем, кто установил и запустил проект, следует предположить, что любые учетные данные, доступные в среде litellm, могли быть раскрыты, и отозвать/сменить их соответствующим образом. Затронутую среду следует изолировать и тщательно проверить на предмет любых неожиданных изменений и сетевого трафика.
Детали атаки на telnyx (PYSEC-2026-3)
После утечки API-токена из-за взломанной зависимости Trivy, на PyPI были загружены две новые версии telnyx, содержащие автоматически активируемое вредоносное ПО, собирающее конфиденциальные учетные данные и файлы и осуществляющее эксфильтрацию на удаленный API.
Скомпрометированные версии выполняют код во время импорта модуля telnyx посредством модификаций в файле _client.py.
Код загружает следующие этапы с конечных точек на хосте 8_._42.209[.]203, закодированные в WAV-файлы. На хостах Windows вредоносный исполняемый файл размещается в %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\msbuild.exe для обеспечения постоянного присутствия и выполняется. На других системах полезная нагрузка представляет собой скрипт Python. После его выполнения сгенерированные артефакты отправляются на 8_._42.209[.]203.
В версии 4.87.1 обнаружена опечатка, препятствующая автоматическому выполнению вредоносного кода.
В коде используется ключ шифрования, обнаруженный в предыдущих действиях TeamPCP. Следует исходить из предположения о полной компрометации уязвимых систем и всех доступных с них учетных данных. Учетные данные должны быть аннулированы/заменены, а затронутые системы изолированы и проанализированы на предмет вредоносных действий и модификаций.
Две версии были удалены из PyPI, и проект был восстановлен.
После обращения к разработчикам litellm и telnyx, Майк и Сет совместно с каждой командой определили дальнейшие шаги, включая ротацию токенов, удаление некоторых релизов и рекомендации по дальнейшим мерам безопасности, таким как использование механизма trusted publishers(доверенных издателей), которые оба проекта впоследствии внедрили.
В чём особенность этого вредоносного ПО?
Этот класс вредоносных программ отличается от большинства вредоносных пакетов, публикуемых в PyPI, которые в основном публикуются в виде новых пакетов, либо с использованием тайпсквотинга(использование похожих имён доменов или пакетов), либо с целью распространения пакета среди других пользователей в надежде на его установку. Этот вредоносный код «внедряется» в уже широко используемые пакеты с открытым исходным кодом. Внедрение вредоносного кода происходит двумя способами:
Нацеленный на проекты с открытым исходным кодом, имеющие небезопасные репозитории, процессы публикации релизов или аутентификацию.
Нацеленный на разработчиков, устанавливающих последние версии проектов с открытым исходным кодом и похищающих токены и ключи API.
Используя токены и ключи API, полученные с машин разработчиков, авторы вредоносного кода могут дополнительно скомпрометировать другие пакеты с открытым исходным кодом, если будут похищены токены API для PyPI или GitHub. Этот цикл продолжается до тех пор, пока он эффективен в похищении новых учётных данных.
Что делает PyPI для борьбы с вредоносным ПО?
Ежедневный объём создаваемых на PyPI проектов — примерно 700–800, что создаёт большую нагрузку из за масштабов. PyPI сотрудничает с исследователями безопасности из нашего сообщества, которые регулярно сканируют и сообщают о вредоносном ПО через соответствующие каналы, чтобы ускорить процесс устранения угроз.
Ниже представлена хронология событий.

В течение периода атаки атакованные версии LiteLLM были загружены более 119 тысяч раз.
PyPI получил 13 входящих сообщений от обеспокоенных пользователей, используя функцию «Сообщить о проекте как о вредоносном ПО», добавленную ещё в 2024 году, что ускорило проверку и принятие мер.
С момента загрузки до первого сообщения: 1 ч. 19 мин.
С момента первого сообщения до помещения в карантин: 1 ч. 12 мин.
С момента загрузки до помещения в карантин (общее время воздействия): 2 ч. 32 мин.
LiteLLM обычно устанавливается ~15-20 миллионов раз в неделю. В среднем это составляет ~1700 установок в минуту. Примерно ~40-50% всех установок LiteLLM были установлены без указания версии и загружали последнюю версию при каждом запуске установки.
Прим. перев.: Если честно, я не понял как они посчитали ~40-50% установок без указания версии. Атакованные версии litellm 1.82.7 и 1.82.8, но их нет в статистике на pepy.tech. Возможно методом исключения. Если вы знаете как это точно посчитать — напишите, пожалуйста, в комментариях.
Поскольку часть пользователей и проектов используют установку самой последней версии, у исследователей и администраторов PyPI остается очень мало времени для сообщения о вредоносном ПО, его сортировки и помещения в карантин после публикации в популярном пакете. Читайте далее информацию о «периоде охлаждения».

Благодаря нашей группе доверенных пользователей PyPI автоматически ответил на сообщение о взломе telnyx. Эти пользователи добавляют вес любому отчёту, запуская функцию автоматического карантина. Подпишитесь на блог PyPI, чтобы получать обновления нашей системы карантина.
От загрузки до первого сообщения: 1 ч 45 мин
От первого сообщения до карантина: 1 ч 57 мин.
От формы загрузки до карантина (общее время воздействия): 3 ч 42 мин.
Ниже приведены несколько способов сделать использование пакетов Python из PyPI более безопасным и избежать установки вредоносного ПО.
Рекомендации по защите
Период охлаждения в установке зависимостей
Один из способов не утонуть в море входящей информации и дать время для обнаружения и устранения вредоносных программ — использование «периода охлаждения(задержки) в установке зависимостей». Задержки в установке зависимостей — это стратегия для установщиков пакетов (таких как pip, uv и так далее), позволяющая избегать установки пакетов, которые были недавно опубликованы в PyPI. Таким образом, это даёт возможность исследователям безопасности и администраторам PyPI реагировать на сообщения о вредоносных программах.
Задержки в установке зависимостей работают лучше всего, когда они настраиваются «глобально» на машине разработчика и пассивно защищают разработчиков от компрометации при каждом запуске pip или uv. Установка относительного значения, например, «3 дня» («P3D» согласно RFC 3339), означает, что пакеты, выпущенные менее 3 дней назад, не будут установлены.
uv уже поддерживает установку относительной задержки в установке зависимостей с помощью ключа ‑-exclude‑newer. Вы можете настроить этот параметр глобально (в ~/.config/uv/uv.toml) или для каждого проекта в вашем файле pyproject.toml:
[tool.uv] exclude‑newer = "P3D" # «3 дня» в формате RFC 3339
Относительные задержки зависимостей скоро появятся в pip v26.1, который должен стать доступен в апреле этого года. Как только они станут доступны, вы можете установить параметр в файле pip.conf (~/.config/pip/pip.conf):
[install] uploaded-prior-to = P3D
Начиная с pip версии 26.0, вы можете установить абсолютные задержки загрузки зависимостей с помощью pip из командной строки, вероятно, в сочетании с другим инструментом, таким как date, для вычисления абсолютной даты от относительного смещения, например, “3 дня”:
python -m pip install \ --uploaded-prior-to=$(date -d '-3days' -Idate) \ simplepackage
Однако применение задержек загрузки зависимостей повсюду — не панацея! Есть определённые ситуации, когда вам действительно нужна последняя версия пакета как можно скорее, например, при применении патчей для уязвимостей. Задержки загрузки зависимостей следует сочетать со стратегией сканирования уязвимостей, чтобы обновления безопасности для зависимостей вашего приложения не ожидали развертывания. Например, Dependabot и Renovate по умолчанию обходят ограничения на использование зависимостей для обновлений безопасности.
Вы можете вручную обойти ограничения на использование зависимостей в pip и uv, установив значение «текущий день», чтобы получить актуальную последнюю версию:
python -m pip install \ --uploaded-prior-to=P0D \ simplepackage==26.3.31
Блокировка зависимостей
Установка пакета из PyPI без «блокировки» означает, что при каждом запуске команды pip install может появляться новый код. Это открывает возможности для немедленной установки пакета и выполнения вредоносного ПО.
Если вы разработчик приложения, использующего пакеты из PyPI, вам следует использовать файлы блокировки как для безопасности, так и для воспроизводимости вашего приложения. Некоторые примеры инструментов, создающих файлы блокировки для приложений:
uv lockpip-compile --generate-hashespipenv
Обратите внимание, что pip freeze не создает файл блокировки зависимостей: файл блокировки должен содержать контрольные суммы/хеши архивов пакетов, чтобы быть безопасным и воспроизводимым. pip freeze только записывает пакеты и их версии. pip работает над экспериментальной поддержкой стандарта pylock.toml через подкоманду pip lock.
Ваша защита как сопровождающего проектов с открытым исходным кодом
Если вы являетесь сопровождающим проекта с открытым исходным кодом на PyPI, вы можете внести свой вклад в защиту пользователей от компрометации. Мы рекомендуем три подхода:
обеспечение безопасности ваших рабочих процессов выпуска релизов
использование Trusted Publishers (доверенных издателей)
добавление 2FA (двухфакторной аутентификации) ко всем учётным записям, связанным с разработкой открытого исходного кода
Обеспечение безопасности процесса выпуска новых релизов
Если вы используете систему непрерывного развёртывания для публикации пакетов в Python — эти процессы являются целью для злоумышленников. Вы можете предотвратить бо'льшую часть угроз, применив эти рекомендации по безопасности:
Избегайте небезопасных триггеров. Workflows, которые могут быть запущены злоумышленником, особенно с входными данными, которые он контролирует (например, заголовки запросов на слияние, заголовки веток), в прошлом использовались для внедрения команд. В частности, триггер pull_request_target из GitHub Actions сложно использовать безопасно, и его следует избегать.
Очистка параметров и входных данных. Любой параметр или входной параметр workflows, который может быть преобразован в выполняемую команду, потенциально может быть использован злоумышленниками. Проверяйте значения, передавая их в качестве переменных окружения командам, чтобы избежать атак с внедрением шаблонов.
Избегайте изменяемых ссылок. Блокируйте или закрепляйте зависимости workflows. Отдавайте предпочтение использованию SHA‑хешей коммитов Git вместо тегов Git, поскольку теги доступны для перезаписи. Поддерживайте файл блокировки для зависимостей PyPI, используемых в workflows.
Используйте развертывание с возможностью проверки. Trusted Publishers for GitHub поддерживает «среды GitHub» в качестве обязательного шага. Это означает, что публикация вашего пакета в PyPI требует проверки вашей учетной записи GitHub, что повышает порог для взлома для злоумышленника.
Если вы используете GitHub Actions в качестве поставщика непрерывного развертывания, мы настоятельно рекомендуем инструмент «Zizmor» для обнаружения и исправления небезопасных workflows.
Использование доверенных издателей вместо API‑токенов
Если платформа, которую вы используете для публикации в PyPI, поддерживает доверенных издателей (GitHub, GitLab, Google Cloud Build, ActiveState), то вам следует использовать доверенных издателей вместо API‑токенов.
API‑токены PyPI являются «долгосрочными», то есть, если они будут украдены злоумышленником, он сможет использовать токен гораздо позже, даже если вы не обнаружите первоначальную компрометацию. Доверенные издатели используют сравнительно недолговечные токены, то есть их необходимо использовать немедленно, и они не требуют ручной «ротации» в случае компрометации.
Доверенные издатели также предоставляют ценный сигнал для последующих пользователей через цифровые аттестации. Это означает, что пользователи могут обнаружить, когда релиз не был опубликован, используя стандартный рабочий процесс выпуска релизов, что, вероятно, привлечет больше внимания.
Добавление двухфакторной аутентификации (2FA) к учетным записям разработчиков открытого исходного кода
Возможно, мы начинаем повторяться, но двухфакторную аутентификацию следует использовать для всех учётных записей, связанных с разработкой открытого исходного кода, а не только для PyPI. Подумайте об учётных записях, таких как системы контроля версий / платформы для создания программного обеспечения (GitHub, GitLab, Codeberg, Forgejo) и ваш почтовый провайдер. PyPI требует включения 2FA для публикации пакетов с начала 2024 года, но включение устойчивой к фишингу двухфакторной аутентификации, например, с помощью аппаратного ключа, может обеспечить дополнительную защиту.
Как вы можете поддержать подобную работу?
Работа в области безопасности не бесплатна. Вы можете поддержать работу по обеспечению безопасности в Python Package Index, оказав поддержку Python Software Foundation (PSF). Если вы или ваша организация заинтересованы в спонсорстве или пожертвованиях в PSF, чтобы мы могли продолжать поддерживать Python, PyPI и его сообщество, ознакомьтесь с программой спонсорства PSF, сделайте пожертвование напрямую или свяжитесь с нашей командой по адресу sponsors@python.org!
Работа Майка Фидлера и Сета Ларсона в качестве инженера по безопасности и защищенности PyPI и разработчика‑резидента по безопасности в Python Software Foundation поддерживается Alpha Omega.
Ещё можете подписаться на тг канал https://t.me/todocore, который я очень вовремя создал, хаха <:-)
Вы можете выделить фрагмент текста и использовать ⌘/CTRL + Enter для отправки сообщения об ошибке.
