LiteLLM 1.107.0 악성 배포 사고: 영향 확인과 대응법

2026년 10월 21일, 공격자가 LiteLLM의 공식 릴리스 파이프라인을 장악해 악성 litellm==1.107.0을 PyPI와 Docker 이미지로 배포했습니다. 이 버전에는 자격증명 탈취기와 매시간 원격 코드를 내려받는 로더가 들어 있고 둘 다 Python이 시작될 때마다 실행됩니다. 코드에서 LiteLLM을 import하지 않아도 마찬가지입니다. LiteLLM의 사고 보고서는 1.107.0이 한 번이라도 돌았던 서버, CI 작업, 컨테이너를 모두 침해된 것으로 봅니다. 처음부터 다시 구축하고 접근 가능했던 비밀 값을 전부 교체하라고 권고합니다.
PyPI에 올라와 있던 시간은 11:39:51부터 약 13:23(UTC)까지로 두 시간이 채 안 됩니다. 그래도 피해 규모를 가볍게 볼 수 없습니다. pypistats 기준(2026년 10월 22일 조회) LiteLLM은 하루 약 343만 회, 한 달 약 9,200만 회 다운로드되는 패키지입니다. LiteLLM 릴리스 과정이 뚫린 것도 올해 들어 두 번째입니다.
핵심 요약
- 악성 버전은
litellm1.107.0 하나입니다. 휠 7개 모두에 악성코드가 들어 있었습니다. LiteLLM은 1.106.2나 사고 이전에 나온 버전으로 고정하라고 안내합니다. - Docker 이미지도 오염됐습니다. GHCR과 Docker Hub의
v1.107.0,latest,main-latest,main-stable태그가 11:46:56(UTC)부터 GHCR은 13:51까지, Docker Hub는 14:20까지 악성 이미지를 가리켰습니다. - 악성코드는 SSH 키, 클라우드·쿠버네티스 자격증명, CI/CD 비밀 값, AI 코딩 도구 토큰, LiteLLM 프록시 DB에 저장된 LLM 공급자 API 키를 빼 갑니다. 이후 매시간 공격자 서버에서 추가 코드를 받아 실행하려 합니다.
- 공격자는 LiteLLM 개발자 3명의 GitHub CLI 자격증명을 손에 넣었습니다. 이를 이용해 브랜치 보호를 무력화하고 비공개 릴리스 워크플로가 이름이 비슷한 가짜 저장소
Berri-AI/litellm의 코드를 빌드하도록 바꿨습니다. - 패키지를 지우는 것만으로는 부족합니다. 악성 파일을 지우고 백그라운드 데몬을 종료하고 환경을 다시 만들고 자격증명을 교체해야 합니다.
LiteLLM 1.107.0에 무슨 일이 있었나
LiteLLM은 BerriAI가 만든 오픈소스 Python 라이브러리이자 프록시 서버입니다. 100개가 넘는 모델 공급자를 OpenAI 형식 API 하나로 묶어 줍니다. 많은 팀이 이 프록시를 사내 LLM 게이트웨이로 쓰기 때문에, 보통 DB 안에 OpenAI, Anthropic, Google, AWS Bedrock 같은 공급자의 API 키가 들어 있습니다. GitHub 저장소의 스타는 약 6만 2,000개입니다.
LiteLLM 사고 보고서에 따르면 공격자는 개발자 3명의 GitHub CLI 자격증명을 갖고 있었습니다. 10월 21일 10:08:29(UTC)에 브랜치 보호 규칙이 비공개 릴리스 워크플로에 대한 무단 변경을 막았습니다. 그런데 5초 뒤, GitHub 조직 소유자 계정의 자격증명이 보호 규칙을 무시하고 변경을 적용했습니다. 바뀐 워크플로는 진짜 BerriAI/litellm과 하이픈 하나만 다른 Berri-AI/litellm에서 코드를 가져와 빌드했습니다. 두 번째로 탈취된 자격증명이 프로덕션 승인 단계를 통과시켰고 파이프라인은 결과물에 서명해 그대로 배포했습니다.
악성 패키지는 LiteLLM의 진짜 파이프라인에서 나왔습니다. PyPI 토큰이 털린 것이 아닙니다. SafeDep의 분석에서도 휠의 빌드 메타데이터는 BerriAI의 평소 빌드 도구와 일치했습니다. 반면 GitHub의 공식 v1.107.0 태그에는 악성 파일이 없습니다. 그래서 GitHub 소스와 배포된 패키지를 비교했다면 문제가 드러났겠지만 "공식 파이프라인에서 나온 패키지인가"만 확인했다면 통과했을 것입니다.
토큰이 새어 나간 경로도 보고서에 나옵니다. LiteLLM은 Claude Code가 응답 본문에 사용자의 GitHub CLI OAuth 토큰을 담을 수 있고 응답 본문을 로그로 남기면 그 토큰이 LiteLLM 로그에 기록될 수 있다고 설명합니다. 인터넷에 노출된 사내 LiteLLM 배포에서 정체를 알 수 없는 사용자 계정이 발견됐고 공격자는 이 계정으로 로그를 읽은 것으로 보입니다. LiteLLM은 최근 패치한 취약점이 진입점이었을 것으로 의심하지만 보고서 마지막 업데이트 시점까지 확정하지 못했습니다.
공격 타임라인 (UTC, 2026년 10월 21일)
| 시각 | 사건 |
|---|---|
| 10:08:29 | 브랜치 보호 규칙이 릴리스 워크플로 무단 변경을 차단 |
| 10:08:34 | 조직 소유자 자격증명으로 보호를 우회하고 변경 적용 |
| 10:46:39 | 가짜 저장소 코드로 스테이징 빌드 시작 |
| 11:11:18 | 두 번째 개발자 자격증명으로 프로덕션 승인 통과 |
| 11:39:51~11:40:13 | 악성 휠 7개가 PyPI에 업로드 |
| 11:43:05 | AISLE의 의존성 방화벽이 첫 휠을 탐지 |
| 11:46:56 | 악성 Docker 이미지 배포 |
| 11:53:49 | 세 번째 자격증명으로 워크플로 실행 기록 삭제 |
| 13:23 | PyPI가 litellm==1.107.0 삭제 |
| 13:51 | GHCR 태그 접근 불가 |
| 14:20 | Docker Hub 태그를 모두 삭제하거나 정상 이미지로 재지정 |
출처: LiteLLM 사고 보고서, 탐지 시각은 AISLE.
AISLE에 따르면 첫 휠은 업로드 3분 14초 만에, 7개 전부는 12:00(UTC)까지 탐지됐습니다. PyPI에서 내려간 것은 업로드 후 약 1시간 40분 뒤였고 Docker Hub 태그는 약 2시간 30분 동안 악성 이미지를 내려보냈습니다.
악성 패키지가 하는 일
각 휠은 site-packages에 파일 3개를 몰래 추가합니다. Python의 site 모듈은 인터프리터가 시작될 때 import 줄이 담긴 .pth 파일과 sitecustomize 모듈을 자동으로 실행합니다. 그래서 이 악성코드는 해당 환경의 모든 Python 프로세스에서 돕니다. pip, 테스트 러너, IDE 언어 서버, CI 작업도 예외가 아니고 LiteLLM을 전혀 쓰지 않는 프로세스도 마찬가지입니다.
| 파일 | 역할 |
|---|---|
cook.pth | Python이 시작될 때마다 import cook 실행 |
cook.py | 난독화된 약 60KB 분량의 자격증명 탈취 코드 |
sitecustomize.py | 분리된 백그라운드 데몬을 띄워 매시간 원격 코드를 받아 실행 |
1단계: 자격증명 탈취기
SafeDep은 cook.py에서 수집 모듈 16개를 확인했습니다. 수집 대상은 다음과 같습니다.
- 시스템·네트워크 정보, 브라우저 저장 비밀번호와 방문 기록
- SSH 키, 셸 히스토리, GPG 키, TLS 개인키,
.pem·.key파일 - AWS·Azure·GCP·쿠버네티스·Docker 자격증명과 AWS 인스턴스 메타데이터 자격증명
- GitLab·Jenkins·Terraform·Vault 비밀 값과 다른 프로세스의 환경변수
- Claude Code, Cursor, Copilot, Codex 같은 AI 개발 도구의 토큰
LiteLLM 프록시가 깔린 서버라면 LLM 공급자 API 키가 담긴 DB 테이블까지 읽어 갑니다. 수집한 데이터는 AES-256-CBC로 암호화하고 그 키를 RSA로 감싼 뒤, 진짜 litellm.ai를 흉내 낸 www.litellm[.]dev로 올립니다. 호스트당 한 번만 실행되고 /tmp에 표시 파일을 남깁니다.
2단계: 매시간 도는 로더
sitecustomize.py는 부모 프로세스에서 떨어져 나온 데몬을 만들고 /tmp/remote_code_loader.lock에 잠금을 겁니다. 그리고 매시간 공격자가 관리하는 GitHub 저장소의 파일에서 서버 주소를 읽고 탈취기를 다시 돌리고 그 서버에서 Python 코드를 받아 실행합니다. StepSecurity가 확인한 이 파일의 변경 이력을 보면 릴리스 전날인 10월 20일에 내용이 비워졌고 AISLE이 분석할 때도 비어 있었습니다. 2단계는 실제로 작동하지 않은 것으로 보입니다. 해당 GitHub 계정은 13:40(UTC)쯤 사라졌습니다. 다만 SafeDep은 그 전에 2단계 코드를 받아 간 호스트가 있었을 가능성을 배제하지 않습니다. Windows에서는 로더가 Unix 전용 기능에 의존해 실패하지만 탈취기는 그대로 실행됩니다(StepSecurity).
빼돌린 키는 몇 시간 만에 쓰였다
Wiz의 보고에 따르면, CI 러너와 쿠버네티스 노드에서 빠져나간 AWS 인스턴스 역할 자격증명이 16:20~17:01(UTC), 즉 배포 후 약 4시간 30분 만에 실제로 사용됐습니다. 공격자는 sts:GetCallerIdentity와 bedrock:ListFoundationModels를 호출했습니다. Wiz는 이를 피해자의 클라우드 계정으로 유료 AI 모델을 돌리는 'LLMjacking' 패턴으로 봅니다. 탈취된 자격증명이 사용됐다고 보고한 곳은 아직 Wiz뿐입니다.
우리 시스템도 영향을 받았을까
10월 21일 이후 아래 중 하나라도 해당하면 영향권입니다.
litellm==1.107.0이 설치된 Python 환경. LiteLLM 체크리스트는pip show litellm을 쓰라고 하지만 감염이 의심되는 서버에서 이 명령을 실행하면 Python이 시작되면서 악성코드가 다시 돕니다. Python 없이 먼저 확인하는 편이 안전합니다. lockfile(uv.lock,poetry.lock,requirements*.txt)에서1.107.0을 검색하고find로litellm-1.107.0.dist-info폴더나cook.pth를 찾아보세요.- 위 시간대에 받은
v1.107.0,latest,main-latest,main-stable태그로 띄운ghcr.io/berriai/litellm,litellm-database,litellm-non_root또는 Docker Hub 이미지. LiteLLM이 밝힌 악성 Docker Hub 인덱스 다이제스트는sha256:1bbcb1443bc962e45f5aad53fe3d2c30600e0379715fb6c664cdd3ac126c339e입니다. - PyPI 노출 시간대에 버전을 고정하지 않고 LiteLLM을 설치한 CI 작업.
서버에서 찾아볼 침해 지표는 다음과 같습니다.
site-packages안의cook.pth,cook.py,sitecustomize.py, 그리고litellm-1.107.0.dist-info폴더/tmp/.pc_once_72129118c59f5636c0bb(이미 데이터 업로드 완료)와/tmp/remote_code_loader.lock(로더 실행됨)- Python 프로세스의 환경변수
PRIVCOLLECT_ACTIVE=1 - 부모 PID가 1이고 작업 디렉터리가
/인 분리된 Python 프로세스 www.litellm[.]dev나raw.githubusercontent[.]com/letters9813/...로 나가는 트래픽, Python 프로세스의169.254.169.254요청
LiteLLM 보고서는 이 흔적이 하나도 없다고 해서 안전이 증명되는 것은 아니라고 강조합니다.
LiteLLM에 따르면 1.106.2와 1.107.0 릴리스 후보(rc) 같은 이전 버전, 그리고 비공개 레지스트리에서 받는 엔터프라이즈 고객은 영향이 없습니다.
정리 방법과 교체해야 할 자격증명
LiteLLM이 안내하는 순서는 이렇습니다.
- 감염된 환경에서
pip install부터 실행하지 마세요. Python이 시작될 때마다 악성코드가 다시 실행됩니다. - 감염된 모든
site-packages에서cook.pth,cook.py,sitecustomize.py와 해당__pycache__파일을 지웁니다. /tmp/remote_code_loader.lock을 잡고 있는 데몬을 종료합니다.litellm==1.106.2로 고정해 다시 설치합니다. 가상환경과 이미지를 처음부터 다시 만드는 편이 더 좋습니다.- 서버가 외부 인터넷에 접근할 수 있었다면 데이터가 이미 나갔다고 가정합니다. 인스턴스·태스크 IAM 역할, LiteLLM 프록시 DB에 저장된 모든 공급자 키, LiteLLM 마스터 키와 가상 키,
DATABASE_URL비밀번호, 서버에서 돌던 모든 프로세스 환경변수의 비밀 값을 교체합니다. - AWS라면 설치 시점 전후로 인스턴스 역할의
GetCallerIdentity호출이 있었는지, 사내 네트워크 밖에서 그 역할의 자격증명이 쓰였는지 CloudTrail에서 확인합니다.
개발자 노트북도 똑같이 챙겨야 합니다. 탈취기는 Claude Code, Cursor, Copilot, Codex 토큰과 SSH 키, 브라우저에 저장된 비밀번호를 노리므로, 1.107.0을 설치한 노트북이라면 이것들도 다시 발급해야 합니다.
LLM 게이트웨이가 공급망 공격의 표적이 되는 이유
LiteLLM 같은 게이트웨이에는 회사가 쓰는 모든 모델 공급자의 키가 모여 있고 클라우드 자격증명과 DB도 함께 있는 경우가 많습니다. 이 서버의 의존성 하나만 오염돼도 애플리케이션 하나가 아니라 훨씬 넓은 범위가 노출됩니다.
LiteLLM에는 올해 두 번째 사고입니다. 3월에는 1.82.7과 1.82.8이 자격증명 탈취기를 품은 채 배포됐습니다. 당시 공격자는 LiteLLM CI에서 쓰던 Trivy 의존성이 뚫리면서 유출된 자격증명을 이용했습니다. 10월 보고서에 따르면 LiteLLM은 그 뒤 릴리스를 비공개 저장소로 옮기고 Trusted Publishing을 도입하고 Docker 태그를 변경 불가로 바꾸고 이미지 서명을 시작했습니다. 이번 공격자는 진짜 파이프라인 안에서 진짜 관리자 자격증명을 써서 이 장치들을 모두 피해 갔습니다.
사용자 입장에서 얻을 교훈은 이렇습니다. 서명과 PyPI attestation은 패키지가 어디서 빌드됐는지는 증명하지만 빌드에 들어간 코드가 내가 검토한 코드와 같다는 것까지 보장하지는 않습니다. SafeDep 확인 결과 1.107.0에는 PyPI 출처 증명(provenance attestation)이 아예 없었고 정상 버전인 1.106.2에도 없었습니다. attestation을 검사했어도 이상 신호를 잡지 못했을 것입니다. 이번 사고를 막을 수 있었던 습관은 세 가지입니다.
- 정확한 버전을 해시와 함께 고정하세요(
pip install --require-hashes, 또는uv·Poetry lockfile). 업데이트는 빌드할 때마다가 아니라 의도해서 하세요. - Docker 이미지는
latest나main-stable같은 유동 태그 대신 다이제스트로 고정하세요. - 새 릴리스는 하루이틀 지켜본 뒤 프로덕션에 들이세요.
uv의exclude-newer설정으로 이런 유예 기간을 걸 수 있고 악성으로 표시된 패키지를 막는 의존성 방화벽도 있습니다. 이번에 AISLE은 업로드 약 3분 만에 경고를 냈고 PyPI는 약 100분 뒤 릴리스를 격리했습니다.
LiteLLM이 지금까지 취한 조치
보고서에 적힌 조치는 네 가지입니다. PyPI에서 악성 패키지를 지웠고 관리자 자격증명을 회수해 꼭 필요한 최소한으로 줄였습니다. 악성 워크플로 변경을 되돌려 이전 버전으로 복구했고 문제 Docker 태그를 삭제하거나 검증된 정상 이미지로 다시 연결했습니다. 10월 21일 20:30(UTC) 업데이트 기준으로 조사는 진행 중이며 LiteLLM은 침해 지표를 추가로 공개하겠다고 밝혔습니다.
자주 묻는 질문
어떤 LiteLLM 버전이 안전한가요?
LiteLLM은 1.107.0 이전 버전이 모두 안전하다고 밝히고 1.106.2로 고정하라고 권합니다. SafeDep도 1.107.0rc1과 rc2를 정상 버전으로 분류했습니다. 악성코드가 든 것은 PyPI의 1.107.0 정식 릴리스와 사고 시간대에 태그된 Docker 이미지뿐입니다.
코드에서 LiteLLM을 import한 적이 없어도 위험한가요?
해당 환경에 1.107.0이 설치됐다면 위험합니다. 악성코드는 Python이 시작될 때 자동으로 실행되는 .pth 파일과 sitecustomize.py를 이용합니다. 그 환경의 모든 Python 프로세스가, pip까지 포함해서 악성코드를 실행했습니다.
LiteLLM 1.107.0을 삭제하면 끝인가요?
아닙니다. 악성 파일은 site-packages에 남고 매시간 도는 데몬도 계속 실행되며 이미 빼돌린 자격증명은 여전히 유효합니다. LiteLLM은 파일 삭제, 데몬 종료, 환경 재구축, 접근 가능했던 모든 자격증명 교체를 권고합니다.
LiteLLM Docker 이미지도 영향을 받았나요?
그렇습니다. ghcr.io/berriai/litellm, litellm-database, litellm-non_root의 v1.107.0, latest, main-latest, main-stable 태그가 11:46:56(UTC)부터 GHCR은 13:51까지, Docker Hub는 14:20까지 악성 이미지를 가리켰습니다. 이전 다이제스트나 버전으로 고정한 이미지는 영향이 없습니다.
공격자는 어떻게 공식 파이프라인으로 배포했나요?
LiteLLM 개발자 3명의 GitHub CLI 자격증명을 탈취해서입니다. 그중 조직 소유자 계정으로 브랜치 보호를 무력화했고 바뀐 워크플로가 가짜 저장소 Berri-AI/litellm의 코드를 빌드했습니다. 두 번째 자격증명이 프로덕션 릴리스를 승인했습니다.
출처
- LiteLLM: Contained: Oct 21, 2026 LiteLLM release v1.107.0 Compromised
- GitHub 이슈 #47826: litellm 1.107.0 compromised
- SafeDep: Compromised LiteLLM 1.107.0 on PyPI Installs a Credential Stealer and Backdoor
- AISLE: LiteLLM 1.107.0 on PyPI shipped a credential stealer
- StepSecurity: litellm 1.107.0 Compromised on PyPI
- Socket: LiteLLM PyPI Package and Docker Images Compromised
- Wiz: LiteLLM compromised, steals credentials
- LiteLLM: Security Update, March 2026
- pypistats: litellm 다운로드 통계
- Python 문서: site 모듈
- PyPI 문서: attestations
- uv 문서: 설정 레퍼런스