← 回首頁
EN繁中

AI 推論伺服器的新攻擊面:12 小時內被利用的 SSRF

AI 推論伺服器的新攻擊面:12 小時內被利用的 SSRF

你花了一整周把 27B 模型跑上自己的 GPU,vLLM 配好了、ROCm 裝好了、Docker 容器跑起來了。然後你把它接到 LAN 上,讓手機和筆電都能連。

問題是:你的「本地」推論伺服器,現在跟一扇沒鎖的門沒有兩樣。

為什麼這跟你有關

LLM 推論伺服器(vLLM、Ollama、LMDeploy、TGI)本質上是一台無認證的 HTTP 代理,帶著 GPU 上跑的模型和它所在網路的完整可視性。如果它沒有認證機制、又暴露在能到達的網路上,那它就能被當作一個「從裡面打出去」的跳板。

2026 年 4 月 22 日,LMDeploy 的 vision-language 圖片載入函式被證實有 SSRF 漏洞(CVE-2026-33626,CVSS 7.5)。從 GitHub advisory 公開到第一筆確認的野外利用,只用了 12 小時 31 分。(source: Sysdig TRT, CSA Research Note)

攻擊鏈:8 分鐘的偵察

Sysdig 的 honeypot 網絡記錄下了完整的攻擊過程。攻擊者 IP 定位在九龍灣(經代理可能非真實位置),整段 session 只有 8 分鐘,明顯是自動化腳本:

  1. IMDS 探測 — 對 169.254.169.254(AWS Instance Metadata Service)發 image_url 請求,試圖抓取 EC2 實例的臨時 IAM 憑證
  2. 端口列舉 — 掃 Redis (6379) 和 MySQL (3306) 標準端口
  3. 管理介面發現 — 找到一個從外網不可達、但推論伺服器能看到的 HTTP 管理介面
  4. DNS 外洩 — 透過攻擊者控制的 DNS 名稱伺服器回傳內部主機名和 IP

關鍵機制:LMDeploy 的 load_image() 函式(lmdeploy/vl/utils.py)接受 client 傳來的 image_url 參數,直接用 HTTP 去抓取這張圖——但沒有驗證目標 URL 是不是內網位址。攻擊者只要把 image_url 設成 http://169.254.169.254/latest/meta-data/iam/security-credentials/,推論伺服器就會幫你去打那個位址。(source: GitLab Advisory)

修補版本 v0.12.3 加入了 RFC1918 私網位址、loopback、link-local 的封鎖清單。

這不是孤例

CVE 元件 類型 影響 修補版本
CVE-2024-37032 Ollama Path Traversal → RCE 任意檔案覆寫 → 遠端程式執行 v0.1.34 (2024)
CVE-2025-9141 vLLM 不安全反序列化 (eval) 工具呼叫參數直接 eval() → RCE v0.10.1.1 (2025)
CVE-2026-33626 LMDeploy SSRF 內部網路偵察、IAM 憑證擷取 v0.12.3 (2026-04)

(source: Wiz Research, GitHub GHSA-79j6-g2m3-jgfw, GitLab Advisory)

共同模式:預設無認證 + 可從網路到達 + 有內部網路可視性。

CVE-2025-9141 特別值得注意:vLLM 的 Qwen3-Coder tool parser 在解析工具呼叫參數時,對不認識的資料型別直接調用 Python 的 eval()。任何能讓模型把任意字串塞進 tool call 參數的輸入,都能在 GPU host 上執行。CVSS 向量:AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H。(source: GitHub Advisory)

你的 homelab 怎麼防

1. 永遠不要讓推論端口直接對外

# vLLM 預設只綁 127.0.0.1,這很好
docker run -d -p 127.0.0.1:8000:8080 vllm/vllm-openai ...

# 需要多機存取?用 reverse proxy + 認證
# Caddy 範例:
# Caddyfile
inference.yourdomain.com {
    reverse_proxy 127.0.0.1:8000
    headers {
        # 加上 Bearer token 檢查(用 reverse_proxy 的 request_header)
    }
}

或者更簡單:SSH 隧道 / WireGuard 把流量封進 LAN,不開任何 inbound port。

2. 加認證層

vLLM 0.24+ 支援 --api-key:

docker run -d -p 127.0.0.1:8000:8080 \
  -e VLLM_API_KEY=sk-your-secret \
  vllm/vllm-openai serve ...

Ollama 本身不支援認證,必須靠 reverse proxy(Caddy、Nginx、Authelia)擋在前面。

3. 網路分區

推論容器不該跟你的資料庫、管理介面在同一個 flat subnet。Docker 自訂 bridge network + firewall rule:

# 只有反向代理能到達推論容器
iptables -A DOCKER-USER -i eth0 -p tcp --dport 8000 -j DROP
iptables -A DOCKER-USER -i docker0 -p tcp --dport 8000 -j ACCEPT

4. 追蹤 CVE 並設定 patch SLA

12 小時的利用窗口意味著「下週再更新」已經不夠。實務做法:

  • 訂閱你用的推論引擎的 GitHub Release / Security Advisory
  • 容器映像定期 rebuild(docker pull + docker compose up -d)
  • 如果你的推論伺服器是關鍵路徑(agent 的 brain),設定 24 小時內的 patch SLA

5. 用 Trivy 掃映像

我現在每週跑一次 Trivy 掃容器映像(走 systemd timer),有 CRITICAL/HIGH finding 就進報告:

trivy image --severity HIGH,CRITICAL --image-src docker vllm/vllm-openai:latest

If You're Stuck

  • connection refused 連到自己的推論伺服器 → 檢查是不是綁了 127.0.0.1 但你從另一台機器連。改成 0.0.0.0 或加 --network host,但記得加認證
  • Docker 容器內連不到宿主機 → 用 host.docker.internal(macOS/Windows)或 172.17.0.1(Linux),或加 --add-host=host.docker.internal:host-gateway
  • vLLM 啟動後 API 回 401 → 檢查 VLLM_API_KEY env var 是否傳進容器,client 端的 Authorization: Bearer header 是否對得上
  • Ollama 暴露後被掃到 → 先用 curl http://target:11434/api/tags 確認 model list 是否洩漏,然後加 reverse proxy 或收回 OLLAMA_HOST
  • CVE-2025-9141 影響你嗎 → pip show vllm | grep Version 看是否 < 0.10.1.1,且啟動參數有 --tool-call-parser qwen3_coder。兩者都符合就要升級

Sources