MAS-SZZ 論文閱讀分析:很多漏洞回溯真正失手的,不是 git 不夠會追,而是一開始就追錯行
本文由 AI 產生、整理與撰寫。
論文基本資訊
- 論文標題:MAS-SZZ: Multi-Agentic SZZ Algorithm for Vulnerability-Inducing Commit Identification
- 作者:Sicong Cao、Jinxuan Xu、Le Yu、Jing Yang、Xingwei Lin、Linlin Zhu、Fu Xiao
- 年份:2026
- 來源:arXiv:2604.24398
- 論文連結:https://arxiv.org/abs/2604.24398
- DOI:10.48550/arXiv.2604.24398
- 主題:AppSec、Vulnerability Research、Code History Analysis、LLM Agents、Software Supply Chain、Secure Maintenance
很多團隊在看 CVE patch 時,第一反應都是「修掉了就好」;但真正麻煩的問題其實是:到底哪一個 commit 才是把漏洞第一次帶進來的那一刀?
這件事看起來像維護細節,實際上卻直接影響:
- 哪些版本真的受影響
- 漏洞檢測模型該學哪段程式碼
- SBOM / VEX / 修補建議到底要回溯到哪裡
- 開發團隊怎麼理解漏洞是怎麼長出來的
這篇 MAS-SZZ 值得看的地方,不是它又把 agent 塞進一個什麼都能加 agent 的場景,而是它抓到現有 SZZ 類方法的兩個老毛病:
很多漏洞 commit 回溯工具真正失手的,不是 git 歷史不夠長,而是一開始就追錯行,後面再怎麼回溯都只是把錯誤走得更遠。
所以這篇的核心 framing,不是「讓 LLM 幫你猜哪個 commit 看起來可疑」,而是把整件事拆成三段:
- 先把漏洞根因講清楚,而且要附證據
- 再從 patch hunk 裡挑出真正和漏洞有關的 anchor statement
- 最後才沿 commit history 一步步往回走,直到找到最早仍含漏洞的版本
這篇在解什麼問題?
SZZ 類演算法的基本想法很直白:從 vulnerability-fixing commit(VFC)往回追,找出 vulnerability-inducing commit(VIC)。問題是,真實世界的修補 commit 很少只有一件事。
同一個 patch 裡常常混著:
- 真正修漏洞的改動
- 順手重構
- 測試補強
- 格式整理
- 其他與安全無關的邏輯調整
如果你把所有 diff 都當成同等重要,回溯很容易被帶去錯的地方。作者把這個問題說得很清楚:既有方法常栽在兩件事上。
- Challenge 1:anchor 選錯。 只盯 deleted / modified lines 很容易被 composite commits、ghost commits 或隱藏在未修改上下文裡的真正 root cause 騙過。
- Challenge 2:backtracking 不夠聰明。 一步回溯太短,多步回溯如果只靠 line similarity 又會 over-trace 或 under-trace。
作者點名的現況也很殘酷:先前 SOTA 的 LLM4SZZ 在人工標註資料集上 accuracy 也只有 40.7%,離可以放心拿去做實務決策還差很遠。
MAS-SZZ 怎麼做?三段式 agent workflow
MAS-SZZ 不把 LLM 當成一個萬能判官,而是拆成幾個責任比較清楚的 agent,讓它們各自做不同判斷。
1. Evidence-Grounded Root Cause Analysis
第一步不是直接追 blame,而是先把漏洞根因寫清楚。MAS-SZZ 會把 CVE 描述、fixing commit 訊息、code diff 一起丟進流程,先由 Auditor 產出根因摘要與對應證據,再交給 Judge 檢查兩件事:
- Evidence Traceability: 每個說法能不能回指到 CVE 或 patch 裡的具體證據
- Logical Consistency: 根因敘述和 commit message 的修補意圖是否一致
這個設計的價值很實際。它不是先問模型「你覺得哪裡有洞」,而是先要求它把後續所有回溯判斷綁在同一份可檢查的 root-cause framing 上。
2. Intent-Driven Anchor Statement Selection
第二步是這篇最關鍵的地方之一:不是所有 patch hunk 都值得拿來回溯。
Reviewer 會先看每個 patch hunk 的語意與上下文,透過 step-forward prompting 分四步理解:
- 程式碼到底改了什麼
- 它怎麼改變執行時行為
- 開發者意圖是 fix、refactor、chore 還是別的
- 最後把這段改動壓成結構化 intent
接著 Evaluator 只保留和漏洞根因真正對得上的 hunk,再由 Locator 在這些 hunk 裡挑出最能代表 root cause 的 statement 當 anchor。
這個設計其實很像在對 diff 做去雜訊:先把「補測試」「整理碼風」「順手調整」這些不該主導回溯方向的東西剝掉,再拿真正會影響漏洞存在與否的那條線往回追。
3. Autonomous Repository Exploration
最後才輪到回溯。Tracer agent 不是像傳統方法那樣只退一步,或一路退到底,而是帶著前面整理出的 root cause 與 anchor statement,逐步檢查每個祖先 commit 裡漏洞是否仍存在。
它用的 stopping logic 也比較合理:當目前 commit 已經看不出漏洞,但前一版還看得出來,就回傳最後一個仍含漏洞的 commit 當 VIC。
換句話說,它真正在做的不是 line ancestry,而是 vulnerability presence judgment。這比單靠 diff 相似度更接近人類安全工程師真的會怎麼判斷。
論文裡的示範案例:問題不一定在 patch 最醒目的地方
作者拿 CVE-2018-1322 當 running example。這個案例裡,Apache Syncope 修補 commit 橫跨五個檔案,但人工標註的真正 VIC 其實集中在 SearchableFields.java 的單一 statement。
這正好說明這篇的核心主張:如果你不先搞清楚哪一段改動真的在修漏洞,而只是把整份 patch 當作回溯入口,最後很容易追到錯的人。
論文也提到在這個例子裡,先前的 V-SZZ 會因為 line similarity 掉下門檻而提早停下來;但 MAS-SZZ 會繼續往前追,因為它判斷的不是「這行長得還像不像」,而是「漏洞條件是否仍然存在」。
實驗怎麼做?
作者用了兩組人工驗證資料:
- V-SZZ dataset:包含 100 個 C/C++ 與 69 個 Java 案例
- Java-SZZ dataset:包含 100 個 Java VIC
比較對象共有七種既有方法:
- B-SZZ
- AG-SZZ
- L-SZZ
- R-SZZ
- MA-SZZ
- V-SZZ
- LLM4SZZ
評估指標是標準的 Precision / Recall / F1-score。
最值得記住的結果
先看 backbone selection。作者試了 GPT-4o-mini、GPT-5-mini、Gemini-3-flash、GPT-5.1、Gemini-3.1-pro、Claude-sonnet-4-6、DeepSeek-V3.2、Qwen3.5-plus。整體來看,重模型普遍比輕模型穩,其中 Gemini-3.1-pro 是作者最後選來做正式比較的 backbone。
在 V-SZZ-c 上,Gemini-3.1-pro 的成績是:
- Precision = 0.73
- Recall = 0.75
- F1 = 0.74
正式和 baseline 比較時,MAS-SZZ 在三個資料切分上都拿到最佳或接近最佳的 recall 與 F1 trade-off:
- V-SZZ-c:0.73 / 0.75 / 0.74
- V-SZZ-j:0.67 / 0.51 / 0.58
- Java-SZZ:0.33 / 0.45 / 0.38
作者總結的關鍵數字是:相對於各資料集上最佳 baseline,MAS-SZZ 的 F1 分別提升了 4.22%、1.75%、65.22%。
這裡最有意思的不是它把 precision 拉到誇張高,而是它做出一個比較能用的平衡。像 V-SZZ 在 V-SZZ-c 上 precision 高到 0.95,但 recall 只有 0.57;換句話說,它很保守,但會漏掉不少真正該追到的 VIC。MAS-SZZ 則是用 0.73 precision / 0.75 recall 拿到更平衡的 F1。
對實務來說,這通常比「極高 precision 但漏很多」更有價值,因為版本受影響分析最怕的,不只是多抓幾個 commit,而是把真正引洞的 commit 直接漏掉。
Ablation study 透露了真正有效的是哪兩件事
這篇另一個值得看的地方,是它沒有只停在「multi-agent 很強」,而是有拆掉元件驗證。
作者發現兩個設計都很重要:
- 拿掉 intent-oriented anchor selection 後,三個資料集上的 precision 分別下降 8.96%、59.52%、3.12%
- 拿掉 autonomous backtracking 後,MAS-SZZ 相對 vanilla 版本的 F1 優勢分別是 54.17%、20.83%、8.57%
這幾個數字很有說服力,因為它們剛好對應這篇開頭點出的兩個核心痛點:
- anchor 選錯,回溯就從錯的地方開始
- 回溯策略太死,追歷史時就會提早停或一路追歪
我怎麼看這篇?
我覺得 MAS-SZZ 最有價值的,不是它把「agent」這個詞放進一個傳統軟體工程問題,而是它把漏洞回溯這件事從純 diff heuristics,推向比較接近語意根因分析 + 證據導向歷史判斷的流程。
這件事為什麼重要?因為很多安全流程表面上是在做 code mining,實際上是在做決策支援:
- 要不要把某版本列入受影響清單
- 這個 patch 是在補根因,還是在補症狀
- 漏洞資料庫裡哪個 commit 應該當 ground truth
如果底層工具只是盯著行號與相似度跑,那你得到的常常是很像答案的歷史噪音;MAS-SZZ 比較像是在問:「這個漏洞在這個 commit 當時,語意上到底還存不存在?」
這個方向我認為是對的,而且很適合未來接到:
- vulnerability management pipeline
- patch triage
- affected-version inference
- 訓練漏洞資料集自動標註
當然,這篇也還不是終點。它仍然依賴 CVE 描述品質、commit message 可讀性,以及 repository context 能不能被工具順利展開。遇到非常髒、非常碎、非常缺上下文的真實專案時,效果能不能維持,還有待後續觀察。
但至少它已經把方向講對了:
很多漏洞歷史分析真正缺的,不是再把 blame 跑快一點,而是先讓系統知道自己到底在追哪個漏洞根因。
結語
MAS-SZZ 這篇論文最值得記住的,不是它用 multi-agent 包裝了一個老問題,而是它把 VIC identification 重新定義成一個更像安全分析、而不只是版本控制技巧的任務:先證據化地理解 root cause,再語意化地挑 anchor,最後根據漏洞是否仍存在來決定何時停止回溯。
如果你在做 AppSec、漏洞資料工程、CVE triage、版本受影響分析,或任何需要把「補這個洞的 patch」往前還原成「最早哪次 commit 把洞放進來」的工作,這篇很值得讀。因為它提醒我們:真正該被追的,不是最像祖先的那一行,而是最早讓漏洞條件成立的那個歷史瞬間。
