Przejdź do treści

Szukaj w Security Magazine

Szukaj w Security Magazine

NewsletterNewsletter
Menu

LiteLLM 1.107.0: zatruta bramka AI i klucze do dostawców

Złośliwa wersja 1.107.0 LiteLLM, open-source'owego proxy do kierowania zapytań między dostawcami modeli językowych, była 21 października dostępna na PyPI przez niespełna dwie godziny; zatrute obrazy kontenerów znikały z rejestrów później, z Docker Hub jako ostatniego. Malware celował w to, do czego taka bramka ma dostęp: klucze skonfigurowanych dostawców AI, a zależnie od wdrożenia także poświadczenia chmurowe i bazę danych. Wniosek dotyczy każdej firmy, która uruchamia proxy LLM u siebie lub u dostawcy IT.

Uchylona skrzynka na klucze z kluczem w zamku w serwerowni, w tle rozmyte szafy rack z niebieskimi diodami.
W tym tekście (5)

Jak zatrute wydanie LiteLLM 1.107.0 wyszło przez oficjalny pipeline

Według raportu LiteLLM z 23 października klucz do wewnętrznej platformy agentowej trafił w maju do publicznego repozytorium i nie został unieważniony. 10 października posłużył do zdobycia tokenu GitHub właściciela organizacji. 21 października atakujący wyłączył tym tokenem ochronę gałęzi, przekierował oficjalny workflow na repozytorium-sobowtóra Berri-AI/litellm i uruchomił wydanie, a kolejnym skradzionym poświadczeniem zatwierdził publikację; pipeline zbudował wydanie, podpisał je i opublikował, po czym trzecim poświadczeniem atakujący usunął zapisy przebiegu workflow. Według LiteLLM bramkę zatwierdzania wydań projekt tymczasowo poluzował na początku tego samego tygodnia (według komunikatu z 21 października: w poniedziałek), tak że wydanie mogło uruchomić i zatwierdzić dowolnych dwóch inżynierów.

Oliver Jensen, Director of Security w LiteLLM, nazwał przyczynę w dyskusji na GitHubie wprost: „use of insufficiently scoped keys combined with failure to revoke after accidental exposure" (zbyt szeroko uprawnione klucze i brak unieważnienia po przypadkowym ujawnieniu). To drugi taki incydent w projekcie w tym roku: w marcu zatrute wydania poszły przez skradzione poświadczenia z CI, w październiku przez skradzione tokeny trzech kont GitHub - właściciela organizacji i dwóch maintainerów - mimo zabezpieczeń wdrożonych po marcu.

Według analizy Socket paczka zawierała pliki startowe Pythona: cook.pth i cook.py uruchamiały złodzieja poświadczeń przy każdym starcie interpretera, także przy pip i niezależnie od tego, czy aplikacja importuje LiteLLM; sitecustomize.py uruchamiał dodatkowy loader, który według Wiz działa tylko na Linuksie i macOS. Złodziej zbiera poświadczenia AWS, Azure i Google Cloud, klucze SSH, tokeny narzędzi deweloperskich i AI, dane przeglądarek i zmienne środowiskowe, a jeśli proxy ma bazę danych, próbuje pobrać z niej zapisane klucze dostawców (Socket: dowód zamiaru, nie skutecznego dostępu). Drugi komponent może pobrać i uruchomić dowolny kod ze wskazanego adresu; według Socket wskaźnik był 21 października pusty, a według Wiz GitHub zdjął repozytorium ze wskaźnikiem tego samego dnia; Socket zastrzega, że kradzież poświadczeń działa niezależnie od tego wskaźnika. Wiz obserwował, że około 4,5 godziny po wykradzeniu atakujący sprawdzał poświadczenia AWS z runnerów CI i węzłów Kubernetes i testował dostęp do modeli w Amazon Bedrock, czyli użycie cudzych kluczy na cudzy rachunek (tzw. LLMjacking).

Wpływ na biznes i pilność: kogo dotyczy, kto może odłożyć

Proxy LLM ma dostęp do kluczy skonfigurowanych dostawców, a zależnie od wdrożenia także do bazy danych i poświadczeń chmurowych. Socket opisuje to jako ryzyko skompromitowanej instalacji, która działa obok tych sekretów. Faktyczny zasięg wycieku zależy od tego, do czego host miał dostęp, dlatego LiteLLM zaleca rotację wszystkich sekretów w jego zasięgu, nie tylko klucza jednego dostawcy.

  • Pilne dziś (kryterium z komunikatu LiteLLM): w jakimkolwiek środowisku uruchomiono Pythona z zainstalowaną wersją 1.107.0, w tym po instalacji bez przypiętej wersji między 11:39 a 13:23 UTC 21 października, albo uruchomiono obrazy v1.107.0, latest, main-latest lub main-stable pobrane między 11:46 a 14:20 UTC. LiteLLM zaleca założyć kompromitację takiego hosta; sama aktualizacja nie wystarcza. W ocenie redakcji trzeba też sprawdzić pliki lockfile, cache i digesty uruchomionych obrazów (miejsca wskazane przez Socket), bo paczka lub obraz pobrane w oknie mogły zostać wdrożone później; dotyczy to serwerów, runnerów CI i stacji deweloperskich.
  • Niedotknięci, ale z jedną czynnością: firma nie użyła tych wersji ani tagów w oknie, a według LiteLLM także klienci prywatnego rejestru enterprise. LiteLLM prosi mimo to użytkowników wersji open source, by na razie przypięli wersję 1.106.2 albo inną jawnie wskazaną, wcześniejszą wersję.

Pytania zarządu do IT lub dostawcy: czy używamy proxy LLM i gdzie leżą klucze do dostawców AI oraz czy sprawdzono okno z 21 października i zrotowano klucze, czy tylko zaktualizowano paczkę?

Rekomendacje

Dziś, jeśli host spełnia kryterium „pilne":

  • Odizolować host lub kontener i zabezpieczyć dowody (procesy, system plików, ruch sieciowy) przed odbudową, zgodnie z zaleceniem Socket.
  • Nie zaczynać od pip install: każdy start Pythona uruchamia malware ponownie.
  • Z poziomu powłoki usunąć cook.pth, cook.py, sitecustomize.py oraz pasujące pliki __pycache__ z każdego dotkniętego katalogu site-packages.
  • Zatrzymać odłączony proces Pythona trzymający blokadę /tmp/remote_code_loader.lock.
  • Odbudować środowisko lub obraz od zera z przypiętą wersją 1.106.2; LiteLLM dopuszcza też samą reinstalację, ale odbudowę uznaje za lepszą.
  • Równolegle z odbudową, z czystego środowiska, zrotować wszystko, do czego host miał dostęp. Według LiteLLM w szczególności: rolę IAM instancji; klucze dostawców z bazy proxy wraz z kluczem master i kluczami wirtualnymi; hasło bazy; sekrety ze środowiska procesów. Według Socket także: klucze SSH, tokeny rejestrów i sesje narzędzi deweloperskich; na liście danych zbieranych przez malware Socket wymienia ponadto tokeny GitHub, poświadczenia narzędzi AI i hasła zapisane w przeglądarkach, więc i one.
  • Przeszukać logi ruchu wychodzącego pod adres exfiltracji www.litellm[.]dev/healthcheck (domena podszywająca się pod projekt, nie litellm.ai) oraz żądania ścieżki /codepy pod dowolną domeną, zgodnie z zaleceniem Socket; to test dostępny także firmom poza AWS.
  • Sprawdzić w CloudTrail wywołanie GetCallerIdentity z roli instancji w okolicy instalacji, a potem użycie poświadczeń tej roli spoza własnej infrastruktury.
  • Plik-marker /tmp/.pc_once_* działa tylko w jedną stronę: jeśli jest, exfiltracja jest potwierdzona (LiteLLM); jeśli go nie ma, nic to nie dowodzi, bo kontenery i czyszczenie katalogów tymczasowych go usuwają.

Dziś, dla wszystkich wdrożeń: przypiąć wersje paczek i digesty obrazów (nie tagi) w proxy LLM i w CI.

W tym tygodniu (w ocenie redakcji): spisać, do jakich kluczy i uprawnień chmurowych bramka AI ma dostęp, i ograniczyć je do potrzebnych; ustalić, z jakimi adresami proxy faktycznie się łączy - jak zauważa w dyskusji kontrybutor projektu, samo proxy woła też GitHub i docs.litellm.ai.

Do zaplanowania: ograniczyć ruch wychodzący z hostów bramki AI do znanych, wymaganych adresów; Jensen nazwał domyślną odmowę ruchu wychodzącego dobrym sposobem uruchamiania proxy, bo działa niezależnie od ustawień aplikacji. W ocenie redakcji rotację kluczy dostawców AI warto wpisać do procedur incydentowych jako standardową czynność.

Podsumowanie

LiteLLM 1.107.0 był dostępny krótko, ale celował w miejsce, gdzie firma trzyma klucze do dostawców AI, a zależnie od wdrożenia także poświadczenia chmurowe i dostęp do bazy. Dla hostów spełniających kryterium „pilne" aktualizacja nie zamyka sprawy: potrzebne są co najmniej reinstalacja z przypiętą wersją (lepiej odbudowa), rotacja poświadczeń i przegląd logów. Dla pozostałych to argument, by bramkę AI objąć regułami systemu z dostępem do sekretów firmy. LiteLLM zapowiada osobną publikację o zmianach w procesie wydawniczym; stan na 25 października.

Źródła