多年來,靜態應用程式安全測試(SAST)一直是安全團隊擴展程式碼審查能力的有效方法之一。
但在設計 Codex Security 時,我們刻意作出了一個設計取捨:我們並非從匯入靜態分析報告,再交由智能代理進行分類處理開始。相反,我們將系統設計為直接從程式碼庫本身出發,當中包括其架構、信任邊界及預期行為並在請求人工介入前,先對發現進行驗證。
原因很簡單:最難發現的漏洞,通常並非單純的資料流問題。這些漏洞往往出現在程式碼看似已實施安全檢查,但該檢查實際上無法保證系統所依賴的安全性。換言之,挑戰不只是追蹤資料如何在程式中流動,而是判斷程式中的防護機制是否真正有效。
SAST 通常被描述為一個清晰的流程:識別不可信輸入來源,追蹤資料在程式中的流動,並標示未經清理即流入敏感位置的情況。這是一個理想而完美的模型,也確實涵蓋大量實際問題。
但在實際操作中,為了能在大規模環境中運作,SAST 必須作出各種近似處理,別是在包含間接調用、動態分派、回呼、反射,以及大量框架控制流程的真實程式碼庫中。這些近似並非處理 SAST 的缺點,而是未執行程式碼而進行分析時的現實限制。
然而,這並不是 Codex Security 不以 SAST 報告作為起點的根本原因。
更深層的問題,在於成功追蹤資料來源與接收點之後會發生什麼。
即使靜態分析能準確追蹤跨越多個函式與層級的輸入,仍需回答一個真正決定漏洞是否存在的問題:
以常見模式為例:程式在渲染不可信內容前,會調用類似 sanitize_html() 的函式。靜態分析工具可以確認該清理程序已執行,但通常無法判斷該處理是否足以應對特定的渲染情境、模板引擎、編碼行為及後續轉換。
問題的關鍵正在於此。問題不只是資料是否到達敏感位置。而在於程式中的檢查是否真正以系統預期的方式限制數值。
換句話說,「程式調用了清理函式」並不等如「系統是安全的」,當中其實存在極大差異。
以下是一個在實際系統中經常出現的模式。
某個網絡應用程式接收 JSON 輸入,提取 redirect_url,使用允許清單的正則表達式進行驗證,再進行網址解碼,最後交由重新導向處理。
典型的資料來源至接收點報告會這樣描述流程:
不可信輸入 → 正則檢查 → 網址解碼 → 重新導向
但真正的問題不在於檢查是否存在,而在於該檢查在後續轉換後是否仍然有效地限制相關數值。
如果正則檢查是在解碼之前執行,它是否仍能如重新導向處理程序所解讀一樣,有效限制解碼後的網址?
要回答這個問題,就需要分析整個轉換鏈,包括正則允許的內容、解碼與正規化行為、網址解析如何處理邊界情況,以及重新導向邏輯如何解析協議與網域。
很多在實際情況中出現的重要漏洞都屬於這一類:操作順序錯誤、部分正規化、解析歧義,以及驗證與實際解讀之間的不一致。資料流本身是清晰可見的。弱點在於約束如何在轉換鏈中傳遞——或未能傳遞。
這並非只是理論上的模式。在 CVE-2024-29041(在新視窗中開啟) 中,Express 曾受開放重新導向問題影響,異常格式的網址可能因重新導向目標的編碼與後續解讀方式而繞過常見的允許清單實作。資料流本身相當直接。更困難、亦真正決定漏洞是否存在的問題,是驗證在整個轉換鏈之後是否仍然成立。
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 如何掃描程式碼庫、驗證發現並提出修正建議,請參閱我們的文件(在新視窗中開啟)。


