Zum Inhalt springen
K Krynex Labs
Alle Artikel
#IT-Sicherheit#Lieferkette#KI-Sicherheit#Python#Docker#Mittelstand

LiteLLM 1.107.0 mit Schadcode: So prüfen Sie, ob Ihre KI-Schlüssel betroffen sind

Am 21. Oktober lag knapp zwei Stunden lang eine verseuchte Version der KI-Bibliothek LiteLLM auf PyPI, auf Docker Hub etwas länger. Sie stiehlt Zugangsdaten und lädt weiteren Code nach. Wir haben unseren eigenen Server durchsucht, zeigen ein kurzes Prüfskript, das ohne Python auskommt, und erklären, warum ein Fund von sitecustomize.py allein noch nichts heißt.

Annett Krusch
LiteLLM 1.107.0 mit Schadcode: So prüfen Sie, ob Ihre KI-Schlüssel betroffen sind (Mit KI erzeugtes Bild) Mit KI erzeugtes Bild. Mehr zur KI-Transparenz

LiteLLM ist eine freie Python-Bibliothek, mit der Programme viele Sprachmodell-Anbieter über eine einheitliche Schnittstelle ansprechen. Es gibt sie auch als Proxy, der die Schlüssel für OpenAI, Anthropic und Co. zentral verwaltet. Genau das macht sie für Angreifer interessant. Wer LiteLLM übernimmt, sitzt an der Stelle, an der in vielen Firmen alle KI-Schlüssel zusammenlaufen.

Am Mittwoch, 21. Oktober, ist genau das passiert. Für knapp zwei Stunden lag auf PyPI, dem zentralen Paketverzeichnis für Python, eine Version 1.107.0, die nicht vom LiteLLM-Team stammte. Sie enthielt laut Hersteller kompilierten Schadcode, der Zugangsdaten stiehlt und Werkzeuge zum Ausführen von fremdem Code nachlädt. Auf Docker Hub war das passende Image noch etwas länger zu haben.

Die meisten Betriebe haben LiteLLM nie bewusst installiert. Das ist der Grund, warum wir darüber schreiben. Bei uns kam es als Abhängigkeit eines anderen Werkzeugs auf den Server, und so geht es vielen.

Was passiert ist

Betroffen sind nach Angaben von LiteLLM ausschließlich diese Pakete:

  • PyPI: litellm==1.107.0, am 21. Oktober von 11:39 bis 13:23 UTC verfügbar, also 13:39 bis 15:23 Uhr deutscher Zeit.
  • Docker Hub: die Tags v1.107.0, latest, main-latest und main-stable, von 11:46 bis 14:20 UTC.
  • GHCR (die Image-Ablage von GitHub): dieselben vier Tags für litellm, litellm-database und litellm-non_root, bis 13:51 UTC.

Wer in diesem Zeitraum ein Docker-Image mit latest gezogen oder eine Python-Umgebung ohne feste Versionsangabe neu gebaut hat, kann den Schadcode bekommen haben. Kunden der privaten Enterprise-Registry von LiteLLM waren laut Hersteller nicht betroffen. Auf PyPI ist 1.107.0 inzwischen entfernt, aktuell ist dort wieder 1.106.2 (Stand 24. Oktober, 7:30 UTC).

Die Sicherheitsforscher von Datadog haben den Schadcode untersucht. Er sucht nach Cloud-Zugängen, SSH- und Git-Schlüsseln, .env-Dateien, Sprachmodell-Schlüsseln, Sitzungen von KI-Programmierwerkzeugen und gespeicherten Browser-Passwörtern. Die Beute geht an litellm[.]dev, eine Domain, die dem echten Namen zum Verwechseln ähnlich ist. Zusätzlich schaut eine Hintertür stündlich nach, ob es neuen Code zum Nachladen gibt. Einen solchen zweiten Teil hat Datadog bisher nicht beobachtet.

Wichtig für die Prüfung: Der Schadcode legt in site-packages die Dateien cook.pth, cook.py und sitecustomize.py ab. Python führt .pth-Dateien und sitecustomize.py bei jedem Start aus, ganz gleich, ob ein Programm LiteLLM überhaupt verwendet. Wer nur den LiteLLM-Ordner löscht, entfernt diese Dateien nicht.

Wie die Angreifer hineinkamen

Am 23. Oktober hat LiteLLM eine Ursachenanalyse veröffentlicht, die frühere Vermutungen aus dem ersten Bericht ausdrücklich korrigiert. Der Anfang liegt fünf Monate zurück. Am 27. Mai landete in einem öffentlichen Repository eine Konfigurationsdatei mit dem Master-Schlüssel einer Agenten-Plattform, die das Team selbst betreibt. Der Fehler fiel schnell auf, der Commit wurde überschrieben, und die offengelegten Schlüssel wurden als zu widerrufen erkannt. Nur der Master-Schlüssel wurde dann doch nicht widerrufen. Am 10. Oktober nutzte ihn der Angreifer und bekam über eine Schnittstelle dieser Plattform den GitHub-Zugang eines Organisationsinhabers zurück. Damit las er über Build-Abläufe weitere Schlüssel von Entwicklern aus, hob am 21. Oktober einen Branch-Schutz auf und ließ die Veröffentlichung von einem Doppelgänger-Repository bauen, Berri-AI/litellm statt BerriAI/litellm.

Das ist die eigentliche Lehre, und sie hat mit Python wenig zu tun. Einen Schlüssel aus einem Repository zu löschen ist nicht dasselbe, wie ihn zu widerrufen. Ein einziger Schlüssel, der öffentlich wurde und gültig blieb, hat Monate später die ganze Lieferkette geöffnet. Fast jeder Betrieb, der mit KI arbeitet, hat inzwischen solche Schlüssel: für den Chatbot, für die Automatisierung, für das Programmierwerkzeug der Entwickler. Die Frage, wo sie überall liegen und wann sie zuletzt getauscht wurden, ist unbequem, aber wichtiger als jedes einzelne Update.

Es ist übrigens nicht der erste Vorfall bei LiteLLM in diesem Jahr. Der Hersteller verweist selbst auf einen früheren im März, nach dem er seine Veröffentlichungskette bereits gehärtet hatte.

Wie wir es bei uns geprüft haben

Wir haben heute Morgen unseren Hauptserver durchsucht, auf dem unter anderem unsere Automatisierungen und Testumgebungen laufen. Gefunden haben wir genau eine Python-Umgebung mit LiteLLM, und zwar in Version 1.81.10. Installiert hatten wir es nie selbst. Es kam im Juni als Abhängigkeit eines quelloffenen KI-Programmierwerkzeugs dazu, das die Version fest vorschreibt. Diese feste Angabe hat uns geschützt: Hätte das Werkzeug nur „irgendein LiteLLM“ verlangt, wäre bei einem Neuaufbau am Mittwochnachmittag 1.107.0 gekommen.

Keine Datei cook.pth oder cook.py, nirgends, auch nicht in den Ablagen der Docker-Images. Keine Marker-Datei in /tmp, weder auf dem Server noch in einem der 26 laufenden Container. Kein Docker-Image mit LiteLLM und keines mit dem Digest, den der Hersteller nennt.

Eine Stelle hat uns kurz stutzen lassen. Die Suche nach sitecustomize.py lieferte 16 Treffer. Keiner davon war Schadcode. 14 sind ein und dieselbe kleine Datei aus der Python-Grundausstattung von Ubuntu, auf dem Server selbst und in mehreren Container-Images, die nur die Fehlerberichte des Systems einbindet. Eine gehört zu einem 3D-Programm, eine zu einem alten eigenen Testaufbau. Wer nach dem Vorfall sucht, wird solche Dateien fast immer finden. Ein Treffer heißt deshalb nicht „betroffen“, sondern „ansehen“. Auf Debian und Ubuntu verrät dpkg -S <pfad>, ob eine Datei zu einem Systempaket gehört. Verdächtig ist eine sitecustomize.py, die in site-packages neben einer cook.pth liegt.

Und noch ein Fehler, den wir selbst gemacht haben: Unsere erste Suche nach cook*.pyc fand Hunderte Dateien, weil das Muster auch auf cookies.pyc und cookiejar.pyc passt. Im Skript unten steht deshalb das genaue Muster.

Das Prüfskript

Das Skript startet bewusst kein Python, auch kein pip. LiteLLM schreibt in seiner Meldung, dass jeder Python-Start in einer betroffenen Umgebung den Schadcode erneut ausführt. Es sucht nur mit find, ls und, wenn vorhanden, docker. Wir haben es auf Linux getestet, auf unserem Server brauchte es gut eine Minute. Es braucht Root-Rechte, damit es alle Verzeichnisse sieht.

#!/bin/sh
# Spuren des LiteLLM-Vorfalls vom 21.10.2026 suchen.
# Startet bewusst kein Python: jeder Python-Start würde den Schadcode erneut ausführen.
SKIP='-path /proc -o -path /sys -o -path /dev'

echo "== 1. Installierte LiteLLM-Versionen"
find / \( $SKIP \) -prune -o -type d -name 'litellm-*.dist-info' -print 2>/dev/null

echo "== 2. Dateien des Schadcodes"
find / \( $SKIP \) -prune -o -type f \( -name 'cook.pth' -o -name 'cook.py' \
  -o -name 'cook.cpython-*.pyc' \) -print 2>/dev/null

echo "== 3. sitecustomize.py (nicht jeder Fund ist schädlich, ansehen)"
find / \( $SKIP \) -prune -o -type f -name 'sitecustomize.py' -print 2>/dev/null

echo "== 4. Marker in /tmp"
ls -la /tmp/.pc_once_* /tmp/remote_code_loader.lock 2>/dev/null

if command -v docker >/dev/null 2>&1; then
  echo "== 5. Docker-Images mit LiteLLM oder dem bekannten Digest"
  docker images --digests --no-trunc | grep -i -e litellm -e 1bbcb1443bc9
  echo "== 6. Marker in laufenden Containern"
  for c in $(docker ps -q); do
    docker exec "$c" sh -c 'ls /tmp/.pc_once_* /tmp/remote_code_loader.lock' \
      2>/dev/null && echo "   ^ Treffer in Container $c"
  done
fi
echo "== Fertig"

So lesen Sie das Ergebnis:

Unter Punkt 1 steht litellm-1.107.0.dist-info. Diese Umgebung hatte die verseuchte Version. Behandeln Sie den Rechner als kompromittiert.

Unter Punkt 2 steht eine Datei. Dasselbe. Der Schadcode war da und lief vermutlich bei jedem Python-Start.

Unter Punkt 4 oder 6 steht eine Datei. Laut Datadog legt der Schadcode /tmp/.pc_once_… an, nachdem er gelaufen ist, und remote_code_loader.lock als Sperre gegen einen zweiten Start. Ein Fund heißt also: Er ist gelaufen.

Nichts gefunden. Das ist ein gutes Zeichen, aber kein Beweis. LiteLLM schreibt selbst, dass ein fehlender Fund nicht belegt, dass eine Umgebung sauber ist. Container, die inzwischen gelöscht wurden, und Build-Rechner in der Cloud sieht das Skript nicht. Fragen Sie deshalb auch bei Dienstleistern nach, die für Sie KI-Anwendungen bauen oder betreiben.

Was bei einem Treffer zu tun ist

LiteLLM empfiehlt, betroffene Umgebungen und Images nicht zu reparieren, sondern neu aufzubauen, mit fester Version, etwa litellm==1.106.2. Dann kommen die Schlüssel, und zwar von einem sauberen Rechner aus: alle Anbieterschlüssel, die im LiteLLM-Proxy hinterlegt sind, Master- und virtuelle Schlüssel, das Passwort der Proxy-Datenbank, die Cloud-Rolle des Rechners und jedes andere Geheimnis, das in der Umgebung eines Prozesses auf diesem Rechner stand. Wer in der Cloud arbeitet, sollte zudem in den Protokollen nachsehen, ob die Zugänge seit dem 21. Oktober von außerhalb benutzt wurden.

Für den Alltag danach bleiben zwei Gewohnheiten, die wenig kosten. Versionen fest angeben, für Python wie für Docker, und latest aus allem streichen, was automatisch neu gebaut wird. Und eine Liste führen, wo welche KI-Schlüssel liegen, damit man sie an einem Vormittag tauschen kann und nicht erst suchen muss.

Was Sie jetzt tun können

Wenn Sie eigene Server oder Entwicklerrechner mit Python oder Docker haben, lassen Sie das Skript heute laufen. Wenn eine Agentur oder ein Dienstleister Ihre KI-Anwendungen betreibt, fragen Sie konkret, ob LiteLLM irgendwo mitläuft und ob am 21. Oktober neu gebaut wurde.

Wie wir prüfen, was KI-Werkzeuge nachladen, bevor es eingespielt wird, beschreiben wir bei der Update-Schleuse. Was ein Sicherheitstest darüber hinaus findet, steht in KI-Pentest: Was ein Sicherheitstest prüft. Eine zweite Lücke aus dieser Woche, die ganz anders funktioniert, haben wir gestern beschrieben: PHP2Shell.

Wenn Sie wissen wollen, wo in Ihrem Betrieb überall KI-Schlüssel liegen und wer sie tauschen kann, sprechen Sie uns an.

Quellen

Alle abgerufen am 24.10.2026.

Stand: 24. Oktober 2026. Der Hersteller untersucht den Vorfall noch und hat seine erste Darstellung bereits einmal korrigiert. Wenn neue Erkenntnisse dazukommen, ergänzen wir den Beitrag.

Häufige Fragen

Welche LiteLLM-Versionen sind betroffen?
Laut Hersteller nur litellm 1.107.0 auf PyPI sowie die Docker-Images mit den Tags v1.107.0, latest, main-latest und main-stable auf Docker Hub und GHCR. Auf PyPI war die Version am 21. Oktober 2026 von 11:39 bis 13:23 UTC verfügbar, auf Docker Hub bis 14:20 UTC, auf GHCR bis 13:51 UTC. Der Quellcode-Tag v1.107.0 auf GitHub enthält die schädlichen Dateien nicht.
Was macht der Schadcode?
Nach Angaben von LiteLLM stiehlt er Zugangsdaten und lädt Werkzeuge nach, mit denen sich fremder Code ausführen lässt. Datadog Security Labs nennt als Ziele unter anderem Cloud-Zugänge, SSH- und Git-Schlüssel, .env-Dateien, API-Schlüssel für Sprachmodelle, Sitzungen von KI-Programmierwerkzeugen sowie gespeicherte Browser-Passwörter. Die Daten gingen an eine Doppelgänger-Domain von LiteLLM.
Reicht es, LiteLLM zu deinstallieren?
Nein. Der Schadcode legt eigene Dateien in site-packages ab, darunter cook.pth und sitecustomize.py, die Python bei jedem Start ausführt, auch wenn LiteLLM gar nicht geladen wird. Datadog schreibt, dass das Löschen des LiteLLM-Ordners diese Dateien nicht entfernt. LiteLLM empfiehlt, Umgebungen und Images neu aufzubauen und alle Schlüssel zu tauschen.
Warum soll man zur Prüfung kein pip starten?
Jeder Start von Python in einer betroffenen Umgebung führt cook.pth und sitecustomize.py erneut aus, so steht es in der Meldung des Herstellers. Auch pip ist ein Python-Programm. Deshalb sucht man zuerst mit Bordmitteln des Betriebssystems nach den Dateien.
Was muss ich tun, wenn ich betroffen bin?
LiteLLM rät, die Umgebung als kompromittiert zu behandeln, auf 1.106.2 oder eine andere ältere, ausdrücklich angegebene Version festzulegen und neu aufzubauen. Zu tauschen sind alle im LiteLLM-Proxy hinterlegten Anbieterschlüssel, Master- und virtuelle Schlüssel, das Datenbankpasswort und jedes Geheimnis aus der Umgebung der Prozesse auf dem Rechner, und zwar von einem sauberen Gerät aus.

Passend dazu