數十年來,靜態應用程式安全測試 (SAST) 一直是資安團隊擴大程式碼審查規模的有效方法之一。
但在打造 Codex Security 時,我們刻意做了一個設計選擇:不先匯入靜態分析報告,供智慧體去分流或安排優先順序。我們改由讓系統直接從程式碼庫本身出發,理解系統的架構、信任邊界與預期行為,並在轉交人工處理之前,先驗證系統找到的問題。
原因很簡單:最難處理的漏洞通常不是資料流問題。這類問題發生在程式碼看似在執行安全檢查,但該檢查實際上無法確保系統預期的安全條件。換句話說,挑戰不只是追蹤資料如何在程式中流動,而是判斷程式中的防護機制是否真正有效。
SAST 常被定位成一條清楚流程:先找出不受信任的輸入來源,接著追蹤資料在程式中的流動,再標記那些資料在未經處理的情況下流入敏感位置的情況。這是一個結構簡潔、概念清楚的模型,而且確實涵蓋了許多真實漏洞。
在實務上,為了在大規模情境下仍可持續運作,SAST 不得不做一些近似處理,特別是在真實程式碼庫中,常見各種間接呼叫、動態派發、回呼、反射,以及大量依賴框架的控制流程。這種取捨並不是 SAST 的缺點,而是在不執行程式碼的前提下,分析程式時必然會碰到的現實限制。
但光是這一點,還不足以構成 Codex Security 為什麼不用 SAST 報告作為起點的主因。
當你成功將資料從輸入來源一路追蹤到敏感操作點之後,接下來該如何判斷是否真的安全。
即使靜態分析能正確追蹤資料在多個函式與各個層級之間的流動,仍需要回答一個真正決定漏洞是否存在的問題:
以常見情境為例:程式碼在呈現不受信任的內容之前,會先呼叫像 sanitize_html() 這樣的函式。靜態分析工具可以看出這個清理程序確實有執行。但通常無法判斷的是,這個清理程序在特定渲染情境、範本引擎、程式碼編寫行為,以及後續的轉換過程中,是否真的足夠。
棘手之處正在於此。問題不只在於資料是否會流到敏感操作點。關鍵在於程式碼中的檢查,是否真正按照系統預期方式來限制資料內容。
換句話說,「程式碼會呼叫清理函式」和「系統是安全的」這兩者之間有很大的差別。
這是一種在實際系統中經常出現的模式。
某個網路應用程式接收一個 JSON 資料,提取 redirect_url,用允許清單的規則運算式進行驗證,再做 URL 解碼,最後把結果交給重新導向處理程式。
典型的「輸入來源到敏感操作點」(source-to-sink) 報告會這樣描述流程:
不受信任的輸入 → 規則運算式檢查 → URL 解碼 → 重新導向
但真正的問題不在於是否有執行檢查,而是該檢查在後續轉換之後,是否還能有效地限制資料內容。
如果規則運算式在解碼前執行,真的能按照重新導向處理程式的解讀方式,限制解碼後的 URL嗎?
要回答這個問題,就必須檢視整個轉換流程:規則運算式允許哪些內容、解碼與標準化如何運作、URL 解析如何處理邊界情況,以及重新導向邏輯如何解析 Scheme 與 Authority。
在實務中,許多重要漏洞呈現出這類型態:操作順序錯誤、部分標準化、解析歧義,以及驗證與實際解讀之間不一致。資料流程是可見的。弱點在於限制條件如何在轉換流程中傳遞,或未能正確傳遞。
這不只是理論上的模式。在 CVE-2024-29041(在新視窗中開啟) 中,Express 曾出現開放重新導向問題。格式錯誤的 URL 可能因重新導向目標的編碼方式與後續解讀方式,而繞過常見的允許清單實作。資料流程本身很單純。真正更難、也真正決定這個漏洞是否存在的問題,是經過整個轉換流程之後,驗證仍否成立。
Codex Security 的核心目標很簡單:用更有力的證據找出問題,減少分流處理的負擔。在產品層面,這代表利用程式碼庫專屬的上下文(包括威脅模型),並在隔離環境中驗證高可信度問題,然後才呈現問題。
當 Codex Security 遇到看起來像是「驗證」或「清理」的邊界時,不會視為已完成的檢查項目,而是會試圖理解程式碼想要保證什麼,再設法推翻這個保證。
實務上,通常會包含以下幾種做法:
- 像資安研究員一樣,在完整程式碼庫上下文中閱讀相關程式碼路徑,找出設計意圖與實作之間的不一致。這包括註解,但模型不一定會相信註解,所以即使在程式碼上方加上 //Halvar says: this is not a bug,如果真的有漏洞,也不會因此被誤導。
- 將問題縮減為可測試的最小單元(例如,針對單一輸入的轉換流程),讓你能在不受系統其他部分干擾的情況下進行推理。從這個角度來看,Codex Security 會抽取細小的程式碼片段,並為其撰寫微型模糊測試器。
- 針對跨越多個轉換階段的限制條件進行整體推理,而不是將各項檢查視為彼此獨立。在適當情況下,這可以進一步形式化為可滿足性問題。換句話說,我們讓模型能存取具備 z3-solver 的 Python 環境,並在需要時加以運用,就如同人類在處理特別複雜的輸入限制問題時所採取的做法。這對於分析非標準架構上的整數溢位或類似問題特別有用。
- 在可行情況下於沙盒化驗證環境中執行假設,區分「可能有問題」與「確實有問題」。以偵錯模式編譯程式碼,並完成完整端對端 PoC,沒有比此更有力的證明。
這是關鍵的轉變:系統不再停留在「存在某項檢查」,而是推進到「不變條件是否成立(或不成立),並提供對應的證據」。模型會為此選擇最合適的工具。
一個合理的反應是:為什麼不兩者並用?先從 SAST 報告著手,再讓智慧體進行更深入的推理。
在某些情況下,預先計算的結果確實有幫助,特別是針對範圍狹窄、已知的錯誤類型。但對於結合上下文、用於發現並驗證漏洞的智慧體而言,從 SAST 報告開始會帶來三種可預期的失敗模式。
首先,此做法可能會導致過早收斂。發現清單就像一張地圖,標示工具已經檢查過的範圍。如果把這張清單當作起點,系統就可能偏向在相同區域投入過多精力、沿用既有理解方式,並忽略不符合該工具思維框架的問題類型。
其次,並用做法還可能引入難以消除的隱含判斷。許多 SAST 的發現本身就帶有對清理、驗證或信任邊界的假設。如果這些假設是錯的,或僅是片面的,把它們帶入推理迴圈,可能會讓智慧體從「調查」轉向「確認或否定」,而這並非我們樂見的方式。
第三,推理系統會更難以評估。如果流程是以 SAST 的輸出作為起點,就難以區分哪些結果是智慧體透過自身分析所發現,哪些則是從其他工具承襲而來。若要準確衡量系統能力,這樣的區隔就很重要,而唯有如此,系統才能持續改進。
因此,我們將 Codex Security 設計為從資安研究的起點開始:直接從程式碼與系統意圖出發,並在將問題轉交人工處理之前,先透過驗證提高結果的可信度門檻。
SAST 工具在其設計目標上表現優異,能強制落實安全編碼標準、捕捉明確的「源到點」問題,並在可預期的取捨下,大規模偵測已知模式。此類工具可以是縱深防禦的重要一環。
本文則聚焦說明,為何用於推理行為並驗證結果的智慧體,不應在一開始就以靜態發現清單作為依據。
此外,純粹「源到點」思維還有一項相關限制值得注意:未必每個漏洞都是資料流問題。許多實際發生的問題屬於狀態與不變條件問題,例如繞過工作流程、授權缺口,以及「系統處於錯誤狀態」的錯誤。對於這類問題,受污染的值並不會流向單一的「危險匯點」。風險在於程式所假設「始終為真」的那些條件。
我們預期安全工具生態系會持續演進:靜態分析、模糊測試、執行期防護,以及智慧體工作流程都將各司其職。
我們希望 Codex Security 真正擅長的,是安全團隊成本最高的那一環,也就是把「看起來很可疑」轉化為「漏洞確實存在、出問題的方式如下,以及如何用符合系統設計意圖的方式修復。」
若想進一步了解 Codex Security 如何掃描程式碼庫、驗證發現結果並提出修復建議,請參閱我們的說明文件(在新視窗中開啟)。


