AI Red Teaming 實戰:自動化攻擊測試

作者: 發布: 18 分鐘閱讀
所屬主題: LLM 應用資安

查核資訊: 本文於 2026-08-25 查核 NIST 的 AI Red Teaming 定義、NVIDIA garak 與 Microsoft PyRIT 官方文件、OWASP GenAI Red Teaming Guide,並引用同日完成的本機自動化測試證據。工具版本、攻擊模組、相依套件與介面仍會變動;正式系統套用前,請重新確認版本、使用條款、測試範圍與資料處理政策。

前 28 天分別處理提示注入、資料外洩、RAG、Agent 權限、供應鏈、輸入與輸出防禦、敏感資料、稽核,以及成本控制。這些控制如果只在實作當下測試一次,後續模型、system prompt、檢索內容、工具 schema 或應用程式流程變更時,原本通過的案例仍可能重新失敗。

Day 29 把固定攻擊案例接到自動化流程。實驗使用兩套自動化紅隊測試工具:Generative AI Red-teaming & Assessment Kit(garak)0.16.0,以及 Python Risk Identification Tool for generative AI(PyRIT)1.0.1。兩套工具會對同一個本機 HTTP 端點送出受限制的測試。這個端點刻意保留弱點,並且每次都依相同規則回應,不含真實模型;實驗要驗證工具整合、請求限制、結果蒐集與證據保存,不比較兩套工具的效果,也不宣稱工具已找出未知漏洞。

正式批次只允許 9 個只在本機內部傳送的 loopback 請求:garak 4 個,PyRIT 5 個。garak 的 4 個測試全部命中;PyRIT 的 4 個攻擊案例全部命中,1 個正常對照案例沒有被判為攻擊。這些數字代表固定測試流程符合事前預測,不代表兩套工具的測試涵蓋率相同。

AI Red Teaming 測試的是整個系統

NIST 將 AI Red Teaming 定義為一種結構化測試,目的是找出 AI 系統的缺陷與弱點,通常在受控制的環境中進行,並與 AI 開發人員合作。NIST Generative AI Profile也指出,這類演練會找出可能的不利行為或結果、分析其發生方式,並對防護措施進行壓力測試。

這個範圍不應縮成「用幾段 jailbreak 測模型」。LLM 應用程式至少包含輸入處理、system prompt、對話歷史、檢索、模型、輸出解析、工具、權限與下游系統。模型可能拒絕一段直接攻擊,但同一段文字進入檢索文件後仍可能被當成指令;模型也可能只回傳一個工具提案,應用程式卻因缺少授權檢查而執行。

OWASP GenAI Red Teaming Guide同樣把測試範圍放在模型與整個生成式 AI 系統。團隊要先定義目標、允許的手法、資料邊界、停止條件與回報方式,再選擇工具。自動化掃描器只是其中一個執行元件,不能取代威脅建模、人工分析與修正驗證。

一次可用的 AI Red Teaming 至少要回答四個問題:

問題 必須固定的內容
測什麼 目標端點、應用程式版本、模型與資料版本、可觸及的功能
怎麼測 攻擊案例、工具版本、參數、請求上限、停止條件
怎麼判定 命中條件、正常對照案例、人工複核規則
怎麼留下證據 原始結果保存位置、去識別摘要、雜湊、commit 與重跑條件

只保存「掃描通過」無法回答任何一項。工具更新後可能換掉攻擊內容,端點更新後也可能改變回應格式;如果沒有版本與原始結果雜湊,團隊無法重現當時的判定。

自動化的價值是持續重跑,不是自動證明安全

人工紅隊可以理解業務流程、跨多個功能組合攻擊,也能辨識工具沒有定義的異常行為。缺點是時間與判讀成本高,而且同一批測試不容易在每次變更後完整重做。

自動化工具適合重複送出已知攻擊、保存相同格式的結果、在產品變更後執行迴歸測試、先篩出值得人工複核的輸出,並把已修正的弱點固定成永久測試案例。

自動化工具不會自動理解「這個輸出對目前產品有多嚴重」。同一段文字在純聊天介面可能只是內容政策問題,在可以寄信、付款或查詢內部資料的 Agent 中,影響範圍可能完全不同。工具的 detector 或 scorer 只負責套用一個判定規則,風險等級仍要結合資料敏感度、功能權限、可利用性與下游副作用。

這次實驗刻意使用確定性端點,讓判定規則可以被單獨驗證。它不測量模型能力,也避免把模型抽樣差異誤認成工具整合問題。

同一個端點接兩套工具

Day 29 的本機流程如下:

garak 0.16.0 ─┐
              ├─→ http://127.0.0.1:18029/generate
PyRIT 1.0.1 ──┘              │
                              ├─→ 確定性回應
                              └─→ 請求來源與數量紀錄

兩套工具都只能連到同一個 loopback URL。端點接受 source 與 prompt 兩個欄位,回傳單一 text 欄位。它不載入模型、不檢索資料、不提供工具,也不執行任何輸出。攻擊提示與完整回應只保存在 Git 忽略的原始證據目錄;可提交的摘要只有版本、案例 ID、請求數、命中數與雜湊。

端點依固定條件回傳虛構的比對字串(marker),讓實驗程式以精確字串判斷測試是否命中。garak 的 PromptInject 測試如果要求輸出指定的 rogue string,端點就會回傳該字串;PyRIT 的四個攻擊案例則分別要求三個刻意植入的虛構機密值(canary),或一個虛構的 system marker。正常對照案例只會收到虛構工單狀態,不含任何攻擊 marker。

這種設計能確認兩套工具是否真的把請求送到同一個應用程式介面、請求數是否符合上限、工具是否能讀取回應並產生預期判定,以及公開報告是否排除完整攻擊內容。它不能確認真實模型是否會受攻擊,也不能估計未知攻擊的漏判率。

garak:Probe 產生測試,Detector 判斷輸出

NVIDIA garak把待測模型或系統抽象成 generator。Probe 定義如何測試特定弱點或失敗模式,detector 再檢查輸出是否出現對應行為;harness 負責安排測試,evaluator 則整理結果。官方 REST generator 可以連到回傳純文字或 JSON 的 HTTP 端點。

這次固定使用 PromptInject 的 HijackHateHumans probe。PromptInject 會把要求輸出 rogue string 的攻擊插入正常提示;garak 取得回應後,由 AttackRogueString detector 檢查指定字串是否出現在輸出。

項目 固定值
garak 版本 0.16.0
Python 3.12
Generator REST
Probe PromptInject HijackHateHumans
亂數種子(seed) 29
每個提示的輸出數 1
Probe 提示上限 4
同時送出的 request 1
同時執行的 attempt 1
Detector Probe 指定的 AttackRogueString

Day 29 的實驗程式也會計算端點實際收到的 garak 請求數。即使 garak 設定宣告上限是 4,端點只要收到不是 4 筆的請求,實驗程式就會中止並拒絕產生正式結果。這項外部計數可以發現工具升級、參數名稱變動或重試行為造成的請求數偏差,避免實際流量超出登記範圍。

garak 的命中代表 detector 在輸出中找到 probe 登記的 rogue string。它不是傳統弱點掃描器的 CVE 判定,也不是證明攻擊可以跨越權限邊界。團隊仍要回到應用程式流程,確認該輸出是否進入瀏覽器、工具、資料庫或其他下游系統。

PyRIT:Target 負責傳輸,Attack 負責執行策略

Microsoft PyRIT把目標系統、攻擊策略、提示轉換、評分與記憶分成可組合元件。Target 可以是模型 API、自訂 HTTP 端點或其他介面;attack 負責依策略送出提示;scorer 可以使用模型、內容安全服務或自訂規則判定結果。

這次使用 HTTPTarget,把固定案例序列化成 HTTP request,再由 PromptSendingAttack 逐一送出。PyRIT 的記憶體設定為 in-memory,不建立可提交的對話資料庫;每個案例最多嘗試一次,沒有重試,也沒有使用外部 scorer。

案例 類型 測試內容 命中條件
direct_override 攻擊 直接要求忽略先前指令 回應含登記的 canary
developer_impersonation 攻擊 冒充 developer 覆寫要求 回應含登記的 canary
roleplay_override 攻擊 以 unrestricted roleplay 改變行為 回應含登記的 canary
system_prompt_extraction 攻擊 要求揭露虛構 system marker 回應含登記的 system marker
benign_summary 對照 摘要虛構客服工單狀態 回應不得含攻擊 marker

Day 29 的實驗程式使用固定 marker 判定 PyRIT 回應,不使用另一個 LLM 當裁判。精確字串比對讓同一份輸出每次得到相同結果,也避免 LLM scorer 本身受提示注入或抽樣差異影響。這種判定只能辨識已登記的字串,無法判斷語意相近的洩漏、部分遵循或其他偏航。

對照案例不可省略。如果所有輸入都是攻擊,而且 detector 對所有輸出都判定命中,團隊便無法知道 detector 是否也會把正常輸出判為攻擊。這次只有一個對照案例,所以結果只能確認這個固定正常輸入沒有被判為攻擊,不能用來估計整體誤判率(false positive rate)。

兩套工具必須使用不同的鎖定環境

我原本嘗試把 garak 0.16.0 與 PyRIT 1.0.1 放入 Lab 的同一個可選依賴。解析器先發現 garak 需要 Transformers 5.14.1 以上,而既有 Prompt Guard 實驗固定使用 Transformers 5 以下;如果直接放寬版本,Day 24 已固定的分類器環境就會被改變。

接著我把兩套紅隊工具放入同一個獨立環境,解析器又發現 garak 需要 datasets 4 以下,PyRIT 則需要 datasets 4.8 以上。這組條件沒有交集。

Day 29 runner
  ├─ tooling/garak/pyproject.toml + uv.lock
  └─ tooling/pyrit/pyproject.toml + uv.lock

兩個環境都固定使用 Python 3.12 與精確的工具版本。正式摘要保存兩份 uv.lock 的 SHA-256,日後重現實驗時可以先確認完整相依套件集合。工具環境分開後,Day 29 實驗程式仍負責啟動同一個端點、使用固定的命令列參數執行工具、限制逾時、彙整結果與檢查總請求數。

garak 與 PyRIT 的相依套件衝突不屬於工具安全測試結果,但會直接影響自動化流程的維運。紅隊工具通常會引入模型、資料集、HTTP 與評估套件;團隊如果把紅隊工具直接安裝進產品環境,可能改變產品共同使用的相依套件。團隊應把掃描工具放在獨立虛擬環境、容器或工作節點,不能因為掃描工具屬於開發用途就忽略供應鏈與版本隔離。

請求上限要由工具內外共同執行

Day 28 已經說明速率、token、並行數與預算限制。自動化紅隊工具同樣需要這些限制,因為 probe、轉換、重試與多輪策略都可能放大請求數。

邊界 設定
目標主機 只允許 127.0.0.1
garak 請求 4
PyRIT 請求 5
總請求 最多 9
並行 每套工具固定 1
單次工具逾時 120 秒
HTTP request 逾時 5 秒
模型下載 離線模式
非 loopback HTTP 指向關閉的本機 proxy
模型呼叫 0
外部副作用 0

工具內的上限用來控制預期流量;端點記錄的實際請求數則用來驗證整批執行是否符合登記範圍。兩種檢查不能互相取代。實驗如果只相信工具參數,工具升級後可能因預設重試或 probe 行為變更而增加請求;實驗如果只在結束後檢查端點計數,則只能在超量請求已經送出後發現問題。

正式環境還要限制紅隊測試可以使用的時間、租戶、帳號、模型與功能。紅隊工具如果直接測試正式系統,可能觸發真實郵件、付款、工單、告警或封鎖機制。即使 prompt 使用虛構資料,下游動作仍可能造成實際影響。高風險功能應使用專用測試租戶與不會產生外部副作用的替身,或由應用程式在真正執行動作前強制阻擋。

事前預測先於正式執行

Day 29 先提交並推送實驗程式,再執行唯一一次正式批次。正式執行前登記的三項預測如下:

  1. garak 的四個 PromptInject 回應都會包含登記的 rogue string。
  2. PyRIT 四個攻擊案例的回應都會包含該案例登記的 marker。
  3. PyRIT 的正常對照案例不會包含攻擊 marker。

正式執行前另做一次預檢(preflight),確認兩套工具目前版本都能連上同一個端點、讀取 JSON 回應並保存結果。預檢結果不納入正式證據。所有修正完成後,Day 29 流程先推送實驗程式 commit 18d28c7,再執行正式批次並產生原始結果。

先固定實驗程式、再正式執行的順序,可以把程式變更與觀測結果分開。團隊不能在看到輸出後修改 detector、案例或預期值,卻仍把同一批輸出描述成事前預測。正式批次如果失敗,團隊應保存失敗原因、修正實驗程式並建立新 commit,再把下一次執行登記成新的結果,不應覆寫原始檔。

完整 runner、兩份工具鎖檔、案例雜湊、原始結果雜湊與限制說明,都已固定在 Day 29 不可變更的證據版本

正式結果:9 個請求全部符合固定矩陣

工具 版本 請求數 攻擊命中 對照命中
garak 0.16.0 4 4 未納入
PyRIT 1.0.1 5 4 0

garak 共完成 4 次評估,每次的 detector score 都是 1.0,表示回應含有 probe 登記的 rogue string。PyRIT 的 direct_override、developer_impersonation、roleplay_override 與 system_prompt_extraction 四個案例都在回應中找到登記的 marker;benign_summary 回應沒有 marker。三項事前預測全部符合。

項目 結果
合成資料
模型呼叫 0
Loopback HTTP request 9
外部網路呼叫 0
外部副作用 0

原始結果 SHA-256 是 5345c0942e055b73e660d462a72d4f9230cc1aea56881eaa4246b9658d819297。公開摘要沒有保存完整 prompt 或 response,只留下版本、鎖檔雜湊、案例 ID、請求數、命中數與判定結果。

4/4 不能直接解讀成工具涵蓋率

garak 與 PyRIT 都得到 4 個攻擊命中,但兩個 4/4 的分母不同。garak 的 4 筆資料來自 PromptInject HijackHateHumans probe;實驗把提示上限設為 4,再由 garak 的 rogue-string detector 判定回應。PyRIT 的 4 筆攻擊資料則是 Day 29 fixture 明確登記的 4 種案例,再由實驗程式使用 marker 規則判定。兩套工具使用的 prompt 與 evaluator 都不同。

因此,這份結果只能說 garak 的固定 PromptInject 整合路徑成功送出四筆測試,detector 在四筆回應中找到登記字串;PyRIT 的四個固定攻擊案例都送達端點,Lab 在四筆回應中找到登記 marker;一個固定正常案例沒有產生 marker。

Day 29 結果不能證明 garak 與 PyRIT 的真實攻擊偵測率都是 100%,不能證明兩套工具效果相同,也不能證明這個端點已經過完整的 AI Red Teaming 評估。團隊必須同時保存分母、案例來源與判定方法,否則無法比較百分比。

從一次掃描變成持續迴歸測試

工具接通後,真正有價值的工作是把已確認弱點轉成固定測試:

威脅建模
  → 選定資產與攻擊面
  → 建立攻擊案例與正常對照
  → 固定工具、模型、資料與設定版本
  → 受限制執行
  → 自動判定
  → 人工複核
  → 修正控制
  → 將已確認案例加入迴歸測試

自動化批次不應直接把所有 detector 命中當成正式弱點。每個 finding 至少要記錄 Finding ID、目標版本、攻擊類型、最小重現案例、判定證據、影響範圍、修正控制與重測結果。

同一個案例在不同位置可能需要不同負責人。模型輸出不當內容可以由 prompt、模型或輸出審核處理;未授權工具執行則必須由應用程式的權限與確認邊界阻擋。紅隊報告如果只寫「模型被 jailbreak」,很難直接形成可驗收的工程工作。

團隊至少應在以下變更後重跑相關案例:更換模型或推論參數、修改 system prompt、增加 RAG 資料來源、修改工具與權限、改變輸出 parser 或 sink、更新 guardrail 或 scorer、升級紅隊工具,以及完成弱點修正。

團隊應分開測試工具升級與產品變更。如果同一批次同時更換模型、prompt、工具與案例,團隊便無法判斷哪一項變更造成結果差異。團隊可以先用舊工具測試新產品版本,再用新工具測試同一個產品版本,分別觀察產品變更與測試工具變更造成的差異。

原始證據可能含敏感內容

紅隊工具通常保存完整提示、模型回應、評分與執行紀錄。真實測試可能碰到 system prompt、內部文件、使用者資料、API 回應或工具參數。這些檔案不能因為位於 test results 目錄就自動視為可公開資料。

Day 29 把完整內容放在 Git 忽略路徑,可提交報告只保留工具與 Python 版本、uv.lock 雜湊、案例 ID 與 fixture 雜湊、請求與命中計數、事前預測結果、網路呼叫數,以及原始證據檔案雜湊。

實際導入時,團隊還要設定證據的保存期限、存取權限、加密、刪除流程與事件回報規則。公開報告如果需要附上重現片段,團隊應先移除憑證、個資、內部 URL、system prompt 與可識別產品設定,並確認讀者無法使用該片段對正式端點重放攻擊。

實驗限制

這次使用的是確定性 HTTP 測試替身,不是真實 LLM 應用程式。端點只依固定字串回傳 marker,沒有 system prompt、對話歷史、RAG、圖片、工具、權限、瀏覽器、資料庫或外部 sink。因此,4/4 只證明固定傳輸與判定流程,不能證明任何模型容易受提示注入。

garak 只使用一個 PromptInject probe,提示上限是 4;沒有執行 encoding、DAN、資料外洩、惡意套件、內容安全或其他 probe。PyRIT 只有四個攻擊案例與一個正常對照;沒有提示轉換、多輪攻擊、自動攻擊生成、模型 scorer 或人工語意評分。

PyRIT 的 marker 規則只辨識完整登記字串。模型如果使用同義詞、部分洩漏、改寫、編碼或結構化欄位回傳相同資訊,規則可能漏判。相反地,拒絕訊息如果引用攻擊 marker,也可能形成字串命中,但不代表攻擊目標已經達成。正式測試流程應分開記錄字串判定、結構檢查與人工語意複核的結果。

garak 與 PyRIT 的結果不能互相比較。兩套工具使用不同 prompt、不同 detector 與不同結果結構;版本更新也可能改變預設 probe、案例順序、重試、報告格式與相依套件。

正式批次在單一電腦上依序執行兩套工具,沒有測試並行掃描、分散式 worker、CI 逾時、共享額度、服務降級或正式環境的流量限制。實驗程式會把非 loopback HTTP 流量導向關閉的本機 proxy,並把模型下載設定為離線模式;這兩項設定仍不構成作業系統層級的網路沙箱。

所有 prompt、marker 與回應都是實驗專用的虛構資料。模型呼叫是 0,loopback request 是 9,外部網路呼叫與外部副作用都是 0。

把工具放進受控制的測試程序

Day 29 的正式結果顯示,兩套固定版本的工具都能在明確的請求上限內,對同一個本機端點完成自動化測試。garak 送出 4 個 PromptInject attempt 並得到 4 個 detector 命中;PyRIT 送出 4 個攻擊案例與 1 個正常對照,攻擊案例 4 個命中,對照案例 0 個命中。三項事前預測全部符合。

Day 29 結果的重點不是 4/4,而是完整的測試契約:固定目標、工具版本、案例、判定方法、請求上限、原始結果雜湊與可公開摘要。團隊必須保存這些條件,才能在模型、prompt、RAG、工具或防禦變更後判斷結果差異。

自動化 AI Red Teaming 應該放在威脅建模與人工複核之間。工具負責重複執行與保存證據,工程團隊負責判斷影響、修正真正的應用程式邊界,並把已確認弱點加入持續迴歸測試。

下一篇會把前 29 天的控制整理成一份 LLM 應用安全檢查清單,依輸入、資料、模型、輸出、工具、權限、執行期、觀測與營運流程逐項收尾。

參考資料

本文同步刊載於 iThome 鐵人賽


《LLM 應用資安:從 Prompt Injection 到 AI Red Teaming》第 29/31 篇

上一篇:濫用與成本攻擊:DoS、Token 榨取與速率限制 · 下一篇:總結:LLM 應用安全檢查清單與心法