AI 讓漏洞報告變便宜,驗證鏈不能一起省掉
一張標記為 Critical 的漏洞工單進入 issue tracker。
它有 CVE 編號、受影響版本、根因分析和 PoC。文字寫得完整,agent 也已經讀過內容,替它貼上最高優先級。這種工單很容易讓小團隊立刻停下原本的工作,開始討論修補版本與公告時程。
但工程師首先該做的事,可能樸素得有點掃興:打開指定版本,找找報告引用的那段程式碼究竟存不存在。
這一步最近變得更重要。AI 降低了產生一份「看起來像漏洞報告」的成本,卻沒有同步降低證明漏洞存在的成本。流暢的敘述可以在幾分鐘內完成;核對版本、建立環境、跑 PoC、分析 crash trace,花的仍是維護者與工程團隊的時間。
如果兩邊的速度差距繼續拉大,大量警報只會把驗證工作推向瓶頸。團隊需要一道門檻,決定每筆警報何時能進入修補佇列。
格式完整,不代表前提成立
SQLite 最近在官方 CVE 紀錄頁上,將六筆被標成 Critical 的 CVE 列為「不是 SQLite 漏洞」,並形容它們看起來是 AI 幻覺。JFrog 對這批報告進一步檢查後,發現其中引用了 SQLite 裡不存在的程式碼,提供的 PoC 也無法證明原本的主張。依 JFrog 的稽核結果,同一帳號提交的 55 筆 advisory 中,有 54 筆被判定為捏造內容。
麻煩的是,這些報告其實寫得很像一回事。它們擁有足以觸發注意力的外觀:正式編號、嚴重度、技術名詞,以及一段讀起來合理的因果關係。
對收到工單的人來說,這些欄位都有用。CVE 編號方便追蹤,嚴重度幫助安排處理順序,根因描述則提供檢查方向。只是它們不能代替重現。若報告指向的函式不存在,或 PoC 在指定版本跑不出聲稱的結果,再高的分數也不會讓缺少的證據自動出現。
安全工單因此需要把兩個問題分開:這件事若成立會有多嚴重,以及目前有多少證據顯示它成立。前者決定已確認風險的優先級;後者決定團隊是否已經能承諾修補。
先把狀態拆開,別讓警報直接等於漏洞
小團隊不需要先導入一套龐大的漏洞管理系統。四個清楚的狀態,通常已經能擋下不少混亂:
待驗證:報告已收到,但版本、程式路徑或 PoC 尚未核對。
重現中:有人負責檢查,環境與前置條件也正在建立。
已確認:團隊取得可重跑的證據,或上游 maintainer 已確認問題。
已駁回/資料不足:主張已被反證,或現有資料不足以繼續判定。
狀態名稱可以自行調整,轉換條件則要先寫清楚。工單不能因為 agent 寫出一段很有把握的摘要,就從「待驗證」跳到「已確認」。它至少要帶著新的證據往前走。
每次轉換最好留下 owner、證據連結和下一個檢查點。誰正在重現?用的是哪個 commit?下一次更新是補齊 build flags,還是等待 maintainer 回覆?這些欄位很普通,卻能防止一張未驗證的 Critical 工單長期佔住佇列頂端,也避免每個接手的人從頭讀一次故事。
證據包要能交給下一個人
我會先把漏洞報告的驗收分成兩層。
第一層是核對身分。受影響的是哪個精確版本或 commit?檔案與函式是否存在?那條 code path 在什麼平台、build flags、輸入和前置條件下可達?如果報告說的是 extension、特定編譯選項或非預設設定,這些條件都要寫出來。
第二層才是重現。最小 PoC 要和隔離環境一起保存,並記錄實際輸出與預期輸出。若主張涉及 crash 或記憶體問題,就附上 crash trace、sanitizer log 與重跑指令。截圖可以幫忙溝通,agent 摘要也能節省閱讀時間,但下一位工程師仍應該能依照 artifact 重新跑出結果。
一張實用的安全工單,不妨保留這些欄位:
state: 待驗證
owner:
affected_revision:
code_path:
platform_and_build_flags:
preconditions:
poc:
reproduction_environment:
actual_result:
expected_result:
evidence_links:
next_checkpoint:這份格式沒有試圖判斷漏洞真假。它只是逼工單回答一個比較務實的問題:下一個人能否從相同前提開始檢查,而不用相信前一個人的語氣?
Agent 適合跑驗證,但不能替自己蓋章
Agent 在這條流程裡其實很有用。它可以核對 advisory 裡的版本與 repo tag、搜尋被引用的函式、整理 build 指令、建立容器、執行 PoC、保留 logs,並把缺少的條件列出來。這些工作耗時,而且大多能留下可檢查的產物。
權限邊界也要跟著寫清楚。Agent 可以把工單從「待驗證」移到「重現中」,因為那表示工作已有人接手;若要改成「已確認」,就該要求可重跑的證據,或由負責的人與 maintainer 做出有紀錄的判定。
讓 agent 用自己的摘要證明自己剛才產生的主張,會形成一個很奇怪的封閉迴路。文字越順,系統看起來越有信心,但團隊得到的仍是同一份未經外部檢查的敘述。
比較健康的做法,是讓 automation 壓縮通往證據的時間。它可以更快找出「指定函式不存在」,也可以更快發現 PoC 缺了必要參數。這兩種結果都很有價值,因為它們讓人知道下一步該補資料、調整假設,還是駁回報告。
無法重現時,先保留不確定性
安全事件很容易把人推向兩個極端。一邊看到 Critical 就立刻承諾修補;另一邊跑一次失敗,便認定報告完全錯誤。實務通常沒有這麼乾脆。
PoC 失敗可能是主張有誤,也可能是版本、平台或編譯條件沒有對齊。找不到報告引用的程式碼,是很強的反證;暫時跑不出 crash,則可能只表示資料還不夠。狀態欄應該容得下這個差異。
因此,「已駁回」和「資料不足」最好共享出口,卻保留原因。前者要記錄哪個前提已被推翻,後者則列出還缺什麼,以及是否值得繼續投入。日後若收到新的 PoC 或 maintainer 回應,團隊才知道該從哪裡重啟檢查。
這也保護了回報者。可重現證據讓報告的可信度跟著資料增加;流程仍應保持輕量,不能反過來成為阻止通報的藉口。好的報告會因為證據完整而更快進入修補,有問題的報告也不會只靠格式和語氣消耗整個團隊。
安全佇列本身也需要被保護
一筆假警報的成本,遠超過某位工程師多跑一次測試。它會打斷正在進行的工作,佔用 maintainer 的注意力,也可能讓需要立即處理的警報被擠到後面。次數一多,團隊會開始用另一種危險的方法節省時間:不再相信佇列裡的任何東西。
這才是 AI 大量生成安全報告時最難處理的後果。報告變多並不必然讓軟體更安全;如果驗證能力沒有跟上,增加的只是待判定敘述,以及維護者對每一筆內容重新建立信任的工作。
小團隊沒有資源驗證所有想像中的風險,更不能把每張寫得像真的工單直接丟進 backlog。把「待驗證」「重現中」「已確認」分開,要求可交接的 evidence packet,再把狀態升級權交給可追責的人,已經能讓流程穩很多。
好的安全 automation 應該縮短通往可重現證據的路,而不是縮短通往「我們相信它」的路。