Złośliwa wersja wyszła oficjalnym kanałem
LiteLLM to popularna biblioteka Pythona i serwer proxy, przez który firmy łączą swoje aplikacje z modelami OpenAI, Anthropic, Google czy Azure. W proxy leżą więc klucze API do wszystkich tych dostawców. 21 października 2026 r. na PyPI i w rejestrach obrazów Docker pojawiło się wydanie litellm 1.107.0, które zawierało skompilowane złośliwe oprogramowanie kradnące dane uwierzytelniające i ładujące zdalny kod. Wydanie zostało podpisane i opublikowane przez prawdziwy proces CI projektu, więc z zewnątrz wyglądało jak zwykła aktualizacja. To drugi incydent tego typu w LiteLLM w tym roku: w marcu złośliwe były wersje 1.82.7 i 1.82.8.
Według wstępnych ustaleń zespołu LiteLLM atakujący zdobył tokeny OAuth GitHub CLI trzech programistów. Jednym z nich zdjął ochronę gałęzi i zmienił workflow wydania, drugim zatwierdził publikację, trzecim usuwał ślady uruchomień. Kod do zbudowania wydania pobrano z repozytorium Berri-AI/litellm, różniącego się od oryginalnego BerriAI/litellm jednym myślnikiem. Źródłem tokenów według zespołu były logi wewnętrznej instancji LiteLLM wystawionej do internetu (to wciąż podejrzenie): Claude Code potrafi umieścić token GitHub CLI użytkownika w treści odpowiedzi, a jeśli bramka AI loguje treść odpowiedzi, token trafia do logów. Sposób wejścia na tę instancję nie jest potwierdzony; LiteLLM wskazuje na niedawno załataną podatność. Numer CVE nie został nadany.
Co robi złośliwy kod
Paczka zapisuje w katalogu site-packages pliki cook.pth, cook.py i sitecustomize.py. Python wykonuje je przy każdym starcie interpretera, także wtedy, gdy żaden skrypt nie importuje LiteLLM. Złośliwy kod zbiera dane logowania do AWS, Azure, Google Cloud, Kubernetes i Dockera, poświadczenia Git, klucze SSH i GPG, dane z przeglądarek, historię powłoki, pliki uwierzytelniające Claude, Codex, Gemini i Cursor oraz klucze dostawców z bazy danych proxy LiteLLM. Dane są szyfrowane i wysyłane na adres podszywający się pod domenę projektu. Na Linuksie i macOS drugi moduł działa jako proces w tle i co godzinę sprawdza plik na GitHubie w poszukiwaniu adresu, z którego pobierze kolejny kod.
Okno ataku i wersje
- Złośliwa:
litellm==1.107.0na PyPI (wszystkie siedem plików wheel), dostępna 21.10 od 11:39 do 13:23 UTC. - Docker Hub: tagi
v1.107.0,latest,main-latest,main-stableod 11:46 do 14:20 UTC; digest indeksu zaczyna się odsha256:1bbcb1443bc9. - GHCR: te same tagi obrazów
litellm,litellm-database,litellm-non_rootod 11:46 do 13:51 UTC. - Bezpieczna:
1.106.2i każda jawnie przypięta wersja wydana przed incydentem. Klienci prywatnego rejestru Enterprise nie byli objęci atakiem.
Kto mógł to pobrać
Okno trwało niecałe trzy godziny, więc najbardziej narażone są systemy, które same pobierają najnowszą wersję: pipeline’y CI instalujące litellm bez numeru wersji, kontenery uruchamiane z tagiem latest lub main-stable i restartowane w tym czasie, środowiska programistów, którzy akurat robili aktualizację. Jeśli macie wersję przypiętą w pliku blokady albo digest obrazu, prawdopodobnie Was to ominęło.
Jak sprawdzić swoje środowiska
- W każdym virtualenv i kontenerze:
pip show litellmalbopip list | grep -i litellm. - Pliki blokady i wymagań:
grep -rn "1.107.0" requirements*.txt poetry.lock uv.lock Pipfile.lock. - Ślady w systemie:
find / -name 'cook.pth' -o -name 'cook.py' -o -name 'litellm-1.107.0.dist-info' 2>/dev/nulloraz nietypowe plikisitecustomize.pyw site-packages. - Proces w tle:
ls -l /tmp/remote_code_loader.lockips aux | grep python. - Obrazy:
docker images --digests | grep litellmi porównanie z digestem podanym wyżej; logi CI z 21.10 między 11:39 a 14:20 UTC.
Brak tych śladów nie dowodzi, że system jest czysty, o czym uprzedza sam producent.
Co zrobić, jeśli wersja 1.107.0 została uruchomiona
- Nie zaczynajcie od
pip installw zainfekowanym środowisku: każde uruchomienie Pythona ponownie wykonuje złośliwy kod. - Usuńcie pliki
cook*isitecustomize*wraz z plikami.pycz każdego site-packages i zabijcie proces w tle. Lepiej przebudować obraz lub virtualenv od zera zlitellm==1.106.2. - Jeśli host miał dostęp do internetu, przyjmijcie, że dane wyciekły. Wymieńcie wszystkie klucze dostawców LLM zapisane w proxy, klucz główny i klucze wirtualne LiteLLM, hasło z
DATABASE_URL, rolę IAM instancji, tokeny GitHub, klucze SSH i każdy sekret ze zmiennych środowiskowych na tym hoście. - W AWS przejrzyjcie CloudTrail pod kątem wywołań
GetCallerIdentityz czasu instalacji, użycia kluczy spoza Waszej infrastruktury i nieoczekiwanego ruchu w Amazon Bedrock. U dostawców LLM sprawdźcie zużycie i rachunki.
Logi bramki AI to też magazyn sekretów
Ten incydent pokazuje dwie rzeczy. Po pierwsze, podpisane wydanie z oficjalnego CI nie gwarantuje bezpieczeństwa, dlatego wersje i digesty obrazów trzeba przypinać, a aktualizacje zależności wdrażać z kilkudniowym opóźnieniem. Po drugie, bramka AI, która loguje pełne zapytania i odpowiedzi, zbiera w logach wszystko, co agenci programistyczni i użytkownicy do niej wyślą, łącznie z tokenami. Takie logi wymagają maskowania sekretów, krótkiej retencji i dostępu tylko dla wąskiej grupy osób, a sama bramka nie powinna być dostępna z internetu.