COMMENTS (0)
댓글은 익명으로 작성되며, 삭제 비밀번호를 설정하면 본인만 삭제할 수 있습니다. 비밀번호를 설정하지 않은 댓글은 누구나 삭제할 수 있습니다.
AI 추론 서버 LMDeploy의 SSRF 취약점이 advisory 공개 12시간 31분 만에 무기화된 사건. load_image() 함수의 검증 누락, 3 phase 공격 흐름, LLM 추론 인프라 보안 공통 패턴까지 정리.
댓글은 익명으로 작성되며, 삭제 비밀번호를 설정하면 본인만 삭제할 수 있습니다. 비밀번호를 설정하지 않은 댓글은 누구나 삭제할 수 있습니다.
패치는 13일 전에 끝나 있었다. 그러나 보안 권고문이 공개된 순간, 정확히 12시간 31분 뒤 공격이 들어왔다. 2026년 4월 22일 새벽, 단 하나의 IP가 어느 회사 서버에 접속해 8분 동안 10건의 요청을 보냈다. 표적은 LMDeploy — 상하이 AI 연구소가 만든 AI 추론 서버다.
이 사건이 보여주는 것은 두 가지다. 첫째, AI 추론 인프라는 이미 공격자의 정찰 대상이다. 둘째, 공개 익스플로잇 코드(PoC)가 없어도 권고문 텍스트만으로 12시간 안에 무기화가 가능하다. 한 가지 단어가 바뀌었다. "패치 공개 = 안전"이 아니라 "권고문 공개 = 카운트다운"이다.
이 글은 한 건을 단계별로 해부한다. 어떤 코드가 취약했고, 공격자는 어떤 순서로 8분을 썼으며, 왜 PoC 없이도 12시간이면 충분했는지. 그리고 LMDeploy 한 건이 vLLM·Triton·Ollama·llama.cpp가 공유하는 더 큰 패턴의 일부라는 사실을 다룬다.
AI 추론 서버는 ChatGPT 같은 AI 모델을 회사 서버에 띄워 자체 서비스로 만든 시스템이다. 외부에 API를 열어두면, 사용자가 보내는 질문을 받아 모델에 통과시키고 답을 돌려준다. 클라우드 환경에서 이 시스템은 두 가지 권한을 동시에 들고 있다. GPU 자원과 IAM 역할(인스턴스에 부여된 클라우드 권한 묶음) 이다. 즉 한 번 침투하면 AI 모델 가중치만 노리는 것이 아니라 클라우드 계정 자체를 들여다볼 수 있다.
LMDeploy는 그중 하나의 도구다. 2024년 OpenMMLab의 MMRazor·MMDeploy 팀이 InternLM 조직 산하에서 개발했고, GitHub 7.8k 스타를 받은 Apache 2.0 오픈소스다. 60개 이상의 LLM과 40개 이상의 비전-언어 모델(VLM)을 지원한다. 기본 포트는 23333, OpenAI 호환 API를 그대로 노출한다. 공식 문서는 이렇게 차별화를 정리한다.
"LMDeploy delivers up to 1.8x higher request throughput than vLLM, by introducing key features like persistent batch (continuous batching), blocked KV cache, dynamic split&fuse, tensor parallelism, high-performance CUDA kernels and so on."
성능 강조 옆에 한 줄이 빠져 있다. 인증은 기본값으로 비활성화돼 있다. 서버를 띄우면 0.0.0.0:23333이 누구에게나 열린다. API 키 옵션은 있지만 명시적으로 켜야 하고, TLS도 옵트인이다. 이 기본값이 다음 사건의 출발점이다.
SSRF는 한마디로 공격자가 보낸 URL을 서버가 대신 가져오는 취약점이다. 사용자 입력에 들어 있는 주소를 서버가 검증 없이 따라가면, 평소엔 외부에서 닿을 수 없는 내부 자원이 외부 호출에 노출된다.
NVD에 등재된 정보는 짧다.
흔한 RCE가 아닌 SSRF다. 보안 위험도는 다음과 같이 갈린다.
무엇이 그렇게 위험할까.
| 항목 | 값 |
|---|---|
| CVE | |
| GHSA | GHSA-6w67-hwm5-92mq |
| 유형 | SSRF (CWE-918) |
| CVSS | 7.5 HIGH (인증 불필요) |
| 영향 버전 | LMDeploy 0.12.2 이하 |
| 패치 버전 | v0.12.3 (2026-04-08 릴리스) |
| 발견자 | Igor Stepansky (Orca Security) |
| 첫 공격 관측 | 2026-04-22 03:35 UTC (권고문 + 12시간 31분) |
핵심은 "이 SSRF가 무엇에 닿느냐"다. LMDeploy 추론 노드가 클라우드에 떠 있다면, 같은 노드에서 접근 가능한 것들은 다음과 같다.
169.254.169.254) — 인스턴스의 IAM 역할 자격증명SSRF가 RCE보다 약해 보인다는 일반적 인식과 달리, AI 추론 노드에서는 IMDS 한 번 성공이 곧 클라우드 계정 탈취다. Sysdig는 이를 "일반 SSRF가 아닌 AI 인프라의 특이점"이라고 짚었다.
문제의 함수는 한 곳에 있다. lmdeploy/vl/utils.py의 load_image() 함수, 64~67줄.
비전-언어 모델은 입력으로 텍스트와 이미지를 함께 받는다. 사용자는 이미지를 직접 업로드하거나, URL로 참조할 수 있다. LMDeploy는 OpenAI 호환 API를 따르므로 image_url 필드를 지원한다. 문제는 이 URL이 어디든 갈 수 있었다는 것이다.
코드는 호스트네임을 해석한 결과가 사설 IP인지 확인하지 않았다. 127.0.0.1을 차단하지 않았고, 링크-로컬 주소 169.254.0.0/16도 막지 않았다. URL 스킴 검증조차 부재했다. 즉 사용자가 image_url로 어떤 내부 주소를 넣어도 서버가 대신 가서 가져왔다.
흥미로운 사실이 하나 있다. 패치는 권고문보다 13일 전에 머지됐다. PR #4447 "fix security issues"가 2026년 3월 27일 머지됐고, v0.12.3은 4월 8일 03:37 UTC에 릴리스됐다. 릴리스 노트에 CVE 번호는 명시되지 않았다. 이른바 사일런트 패치다.
패치 본체는 _is_safe_url() 함수 추가다. 차단 대상은 다음과 같다.
자동 redirect 따라가기도 비활성화됐다. 정확히 일반 SSRF 방어 패턴이다. 그러나 이 13일 동안 권고문은 비공개였고, 사용자들은 자신이 무엇을 패치하고 있는지 몰랐다.
2026년 4월 21일 15:04 UTC, GitHub Advisory가 공개됐다. 그로부터 12시간 31분 뒤, Sysdig가 미리 띄워둔 LMDeploy 허니팟에 IP 103.116.72.119가 접속했다. 홍콩 Kowloon Bay에 위치한 AS400618 Prime Security Corp 네트워크였다. Sysdig는 이를 "실제 운영자가 아닌 프록시 또는 임대 클라우드 인스턴스"로 평가했다.
첫 요청은 두 곳을 향했다.
AWS 메타데이터 서버는 EC2 인스턴스(AWS의 가상 서버)가 자신의 IAM 역할 자격증명을 가져오는 통로다. 정상 요청은 인스턴스 내부에서만 발생해야 한다. SSRF로 외부에서 이 endpoint를 부르게 하면, 응답에는 임시 액세스 키와 시크릿이 포함된다. AWS는 이를 막기 위해 IMDSv2(토큰 기반)를 도입했지만, IMDSv1을 여전히 쓰는 인스턴스가 많다.
Redis 6379번 포트도 같은 시점에 부쳐졌다. 추론 노드 옆에 떠 있는 캐시 서비스에 접근할 수 있는지 측정한 것이다.
5분 정도의 정적 시간 뒤, 공격자는 다른 카드를 꺼냈다. OOB(Out-of-Band) DNS 콜백이다. cw2mhnbd.requestrepo.com이라는 임시 도메인이 등장했다. requestrepo.com은 보안 연구자가 자주 쓰는 OOB 도구로, 도메인을 받으면 그 도메인에 들어오는 모든 DNS·HTTP 요청을 기록해준다.
공격자는 SSRF가 외부 인터넷까지 닿는지 확인하고 싶었다. 응답이 차단되더라도 DNS 조회만 성공하면 도메인 서버 로그에 흔적이 남는다. 이른바 blind SSRF 검증이다.
같은 시점에 /openapi.json을 가져오고, /v1/chat/completions를 정상 호출도 한 번 시도했다. 서버가 살아 있는지, 어떤 endpoint를 노출하는지 표면 감지(enumeration)였다.
마지막 단계는 가장 직접적이었다. 공격자는 /distserve/p2p_drop_connect라는 LMDeploy 고유 endpoint를 시도했다. 이는 분산 추론 클러스터의 노드 간 ZMQ(분산 노드끼리 메시지를 주고받는 라이브러리) 연결을 끊는 관리 기능이다. 한 노드가 죽으면 추론 서비스 전체가 영향받을 수 있다.
이어서 36초 동안 로컬 포트 스윕이 진행됐다. 8080, 3306, 80번이었다. 각각 일반적 HTTP 어드민 패널, MySQL, 일반 웹서버 포트다. SSRF는 이 모든 곳을 한 노드 안에서 두드릴 수 있는 도구가 됐다.
8분 31초 만에 단일 IP가 한 LMDeploy 인스턴스에 대해 IAM 자격증명·내부 데이터베이스·클러스터 교란·내부 포트 스윕을 모두 시도했다. 이 모든 것이 PoC 없이 일어났다.
같은 시기 AI 추론 서버 생태계에 비슷한 패턴이 반복됐다.
공통점은 세 가지다. 첫째, 인증 미적용 기본값. 둘째, 사용자 입력 처리 단계에서 검증 부재(역직렬화·URL·path). 셋째, 추론 노드의 광범위한 권한(GPU + IAM + 내부망 접근).
특히 vLLM은 코드 재사용을 통해 패턴이 확산된 사례다. Oligo Security가 명명한 ShadowMQ는 ZeroMQ + pickle 역직렬화 결함이다. 이 결함은 Meta Llama Stack에서 시작해 vLLM, SGLang, NVIDIA TensorRT-LLM, Modular Max, Microsoft Sarathi-Serve로 복붙 전파됐다. SGLang 코드에는 "Adapted from vLLM"이라는 주석까지 남아 있었다. 한 프레임워크의 위험 패턴이 6개 주요 도구에 동시에 살아 있었다.
n-day 익스플로잇은 새로운 현상이 아니다. n-day는 패치가 공개된 후 아직 패치하지 않은 시스템을 노리는 공격이다. 공개 전 취약점을 노리는 0-day(zero-day)의 반대 개념이다. Mandiant M-Trends 2025 보고서는 평균 TTE(time-to-exploit, 패치 공개부터 실제 공격까지 걸린 시간)가 2024년 5일로, 그 이전 32일에서 급격히 짧아졌다고 정리했다. 그러나 시간 단위 무기화는 다른 차원이다.
같은 분기에 비슷한 사례가 또 있다. Marimo 은 사전 인증 없는 RCE이며 CVSS 9.3을 받았다. 권고문 공개 9시간 41분 만에 Sysdig 허니팟에서 익스플로잇이 관측됐다. 4월 11~14일 사이 662건의 공격 시도가 기록됐고, CISA는 4월 23일 KEV에 등재했다. LMDeploy(12h31m)와 marimo(9h41m)는 6개월 안에 등장한 두 사례다.
세 가지 점이 변했다.
LMDeploy 인스턴스가 침해됐다면 흔적은 어디에 남을까. 공격자가 남길 수밖에 없는 신호 세 가지다.
/v1/chat/completions 호출 본문에 외부 URL 포함: 정상 사용은 보통 사용자 측에서 base64 이미지를 직접 전달하거나, 신뢰된 CDN URL을 쓴다. 사설 IP·메타데이터 IP·OOB 도메인이 image_url에 등장하면 비정상이다.*.169.254.169.254(AWS IMDS), 127.0.0.1로 향하는 자기 자신 호출이 추론 노드 로그에 잡힌다./distserve/*·/openapi.json 비정상 접근: 일반 클라이언트는 이 endpoint를 부를 일이 없다. 외부 IP에서 한 세션 안에 두 종류 모두 호출되면 표면 감지(enumeration) 신호다.방어 측 권고는 단순하다. v0.12.3 이상으로 업그레이드, IMDSv2 강제, 추론 노드 egress 제한(외부 인터넷 접근 차단), 그리고 가능하면 API 인증 활성화. 기본값을 신뢰하지 말 것.
load_image() 함수에서 발생한 SSRF다. 인증 없이 호출 가능하고, AWS IMDS·내부 데이터베이스·클러스터 관리 포트 모두에 닿는다. 패치는 advisory보다 13일 앞선 v0.12.3에 사일런트로 적용됐다.AI 활용 안내 이 글은 AI(Claude)의 도움을 받아 작성되었습니다. 인용된 통계와 사례는 참고 자료에 명시된 출처에 근거하며, 설명을 위한 일부 표현은 각색되었습니다.
면책 조항 본 글은 보안 인식 제고를 위한 교육 목적으로 작성되었습니다. 언급된 공격 기법을 실제로 시도하는 행위는 「정보통신망법」, 「형법」 등에 따라 처벌받을 수 있으며, 본 블로그는 이에 대한 법적 책임을 지지 않습니다.
KW_PROTECT_0