結構化輸出
第 5 階段把每筆存活的發現轉成可被機器讀取的 JSON,符合 report-schema.json,並由零依賴的 Node 驗證器檢查。
schema 是一個 oneOf:一筆發現要嘛是 confirmed(完整 trace、執行與修補),要嘛是 rejected(調查後發現事實有誤)。各處都強制 additionalProperties:false。
// Confirmed 發現——必填欄位
verdictconst "confirmed"標記為已驗證的漏洞。
titlestring簡潔、標準的漏洞標題。
descriptionstring完整說明,含 PoC 與觀察到的輸出。
root_causestring一句話:「[函式] 在 [檔案] 沒有做 [動作],導致 [後果]」。
intended_behaviorstring開發者原本想做的、非漏洞的邏輯。
tracearray (≥2)從 entrypoint → … → sink 的循序步驟;每步 {kind,file,line,scope,description}。第一步須為 entrypoint、最後一步須為 sink。
conditionsarray事實前提(認證等級、角色、設定、時序……)。預設即可利用則為空陣列。
executionobject{attacker_perspective, payloads[], instructions[], expected_result}。
remediationobject{strategy, code_changes[]}——修補。
severityobject{likelihood{score,reason}, impact{score,reason}, overall_severity}。
confidenceobject{score, reason}——記下缺失檔案或模糊的資料流。
// Rejected 發現
verdictconst "rejected"所述行為事實錯誤,或該程式碼路徑不存在。
reasonstring哪些具體主張錯了,附程式碼證據。
// 一筆 confirmed 發現(節錄)
{
"verdict": "confirmed",
"title": "Stored XSS in comment rendering",
"root_cause": "renderComment in views/comment.js does not escape body, allowing script injection",
"trace": [
{ "kind": "entrypoint", "file": "routes/comment.js", "line": 42,
"scope": "createComment", "description": "req.body.text stored unsanitized" },
{ "kind": "sink", "file": "views/comment.js", "line": 17,
"scope": "renderComment", "description": "body interpolated into innerHTML" }
],
"severity": {
"likelihood": { "score": "high", "reason": "any authenticated user can post" },
"impact": { "score": "high", "reason": "fires for every viewer" },
"overall_severity": "high"
},
"confidence": { "score": "high", "reason": "trace verified against source" }
}validate-findings.cjs
一個零依賴的 Node 驗證器。它直接讀 report-schema.json,檢查必填欄位、enum 值、結構限制、additionalProperties,以及 trace 是否 entrypoint → sink。它只做結構檢查——確認 JSON 符合 schema,而非確認發現正確。事實查核是第 6 階段的工作。
node validate-findings.cjs findings.json