Два часа в PyPI лежала библиотека, которая воровала ключи. И её даже не нужно было импортировать
21 октября взломали LiteLLM. Это популярная питоновская библиотека, через которую программы ходят к разным нейросетям по одному интерфейсу. Сам код на гитхабе никто не трогал. Взломали конвейер, который собирает и выкладывает релизы, и через него в PyPI и на Docker Hub уехала версия 1.107.0 с сюрпризом внутри.
В PyPI она провисела примерно два часа, по их собственному отчёту с 11:39 до 13:23 по UTC. Образы в Docker Hub с тегами v1.107.0 и latest были заражены чуть дольше, до 14:20. Вроде мало. Но популярный пакет за два часа успевают скачать и сервера с автосборкой, и люди, которые просто решили обновиться.
Самое неприятное тут в том, как оно запускалось. При установке в папку site-packages клались три файла: cook.pth, cook.py и sitecustomize.py. Файлы .pth Python читает сам при каждом старте интерпретатора, вообще при каждом. Получается, если пакет просто стоит в окружении, вредонос стартует вместе с любым вашим скриптом, даже если в нём нет ни одного import litellm. Дальше он собирал ключи и пароли, до которых мог дотянуться, и подгружал инструменты для удалённого доступа.
Удалить пакет после этого мало, украденные ключи сами себя не отзовут. Все, кто разбирал инцидент, советуют одно и то же: откатиться на 1.106.2, а все секреты, которые видела заражённая машина, считать утёкшими и перевыпускать.
Я пишу ботов и парсеры на заказ, и почти в каждом проекте у меня лежит .env с токеном бота, доступом к базе, иногда с ключом от платёжки. Так что про такие истории я думаю совсем не абстрактно. Вот что я делаю, чтобы меня это задевало поменьше.
1. Версии зависимостей фиксирую точно, через ==. Никаких «поставь последнюю». Обновляю руками, когда сам решил, а не когда сервер сам пересобрался.
2. В Docker не использую тег latest. Тут прямо в тему: заражённым оказался как раз latest.
3. Новую версию популярной библиотеки не ставлю в день выхода. Пару дней подождать почти всегда можно, а такие взломы обычно находят за часы.
4. У каждого проекта свои ключи. Если утечёт один, не придётся бегать и менять всё у всех заказчиков.
5. Токены и пароли заказчик оформляет на себя. Если что-то случилось, он может отозвать их сам, не дожидаясь меня.
На сто процентов ничего из этого не спасает. Если бы я в ту среду в обед пересобирал проект с незафиксированной версией, словил бы то же самое. Но шансов меньше, и разгребать потом меньше.
Кстати, по данным Chainguard, LiteLLM так ломают уже второй раз за семь месяцев. Если у вас где-то стоит litellm без указания версии, гляньте, какая там сейчас.








