Day 10,我把查詢參數 q 放進雙引號包住的 <img src="...">,在本機得到三種不同結果:弱點頁形成獨立的 onerror 並執行探針;編碼頁雖然反射了探針文字,卻沒有新增事件屬性;不反射頁則沒有出現本次探針識別碼。
這三種狀態不能只用「回應中有沒有 onerror」來區分。編碼頁的 src 值裡仍有這段文字,但瀏覽器沒有把它當成屬性。Day 10 的實際 DOM 觀察也符合這個差別。
今天,我把這三組已保存的結果接回 Day 7 的 AI 風險報告流程。我會檢查模型是否保留工具分類,並說清楚「反射」「新增屬性」與「實際執行」各自代表什麼。
Day 7 的 build_evidence() 原本服務於 Day 6 的 HTML 文字情境。它會提供工具摘要、瀏覽器執行狀態、回應節錄與限制。我直接把三組 Day 10 JSON 交給舊函式檢查,每組仍只得到 4 份來源,但都沒有輸出位置 double_quoted_html_attribute,也沒有原始回應與 DOM 的 onerror 獨立屬性真值。
這項資訊必須由證據轉換提供。編碼頁的回應節錄包含 " onerror=",如果只看字串,容易把屬性值裡的文字誤當成新的事件屬性。於是我在 Day 11 建立專用證據轉換:
| 來源 | 提供給模型的本次證據 |
|---|---|
| E1 | 工具分類、q 參數、雙引號 img#result-image 的 src 輸出位置 |
| E2 | 原始 HTML 回應、探針是否反射、解析後的 src 與獨立 onerror |
| E3 | Chrome DOM 中的 src、onerror,以及文字是否留在 src 值內 |
| E4 | alert、對話框訊息、DOM 識別碼與執行真值 |
| E5 | 本機探針的適用範圍與未測項目 |
程式先讀取 Day 10 的三組 JSON、原始回應文字檔及執行摘要,核對 SHA-256、HTML 解析結果、DOM 屬性與分類是否一致,再產生模型輸入。這一步只使用保存的資料,沒有重新啟動測試網站,也沒有再次送出 XSS 探針。
編碼頁的幾個關鍵欄位分別來自原始回應、DOM 與瀏覽器執行紀錄:
E2 probe_token_reflected: true
E2 quote_entity_before_onerror: true
E2 response_handler_attribute_observed: false
E3 onerror_text_inside_src: true
E3 dom_onerror: null
E4 execution_observed: false
quote_entity_before_onerror: true 是從原始 HTML 的 " onerror=" 得到的可核對事實。DOM 裡的 src 含有字面上的 " onerror=",但獨立的 onerror 屬性是 null。因此,我要求報告同時引用「有反射」「沒有新增屬性」與「沒有觀察到本次探針執行」,不能只引用其中一項。
不反射頁也有自己的直接證據:probe_token_reflected: false,而原始圖片的 src 是 /fixed.png。本次識別碼沒有進入回應,分類應為 not_reflected。
我先用已保存的 Day 10 結果乾跑,再用 gemini-3.5-flash-lite 對三組各送出一次請求。三份回答都符合 Day 7 的九欄 JSON Schema,也保留了 confirmed_xss、reflected_but_not_executed 與 not_reflected。當時的逐字引用規則也全部通過。
不過,我逐項對照原始證據時發現:
alert(1) 探針的執行寫成「執行任意 JavaScript 程式碼」,摘要又少引了部分元素與 DOM 識別碼資訊。" 的編碼證據或 dom_onerror: null,並把假設未來編碼失效的情境列為可能影響。根據Google 的說明,JSON 結構正確仍不保證欄位值在語意上正確,應用程式仍須驗證。這次的第一次回答正好提供了具體例子:validation.passed: true 只代表當時寫下的格式與引用規則通過,不能取代作者核對。
我保留第一次的模型原文與驗證檔,另做第二次實驗。新規則要求引用輸出元素、src、q、反射狀態、獨立屬性、alert、DOM 識別碼及限制;編碼組還須引用引號編碼與 src 值內文字,不反射組須引用固定的 /fixed.png。
在本機實驗缺少真實業務情境時,三組的 risk_rating 都必須是 needs_context。編碼與不反射組沒有確認 XSS,本次報告的 possible_impacts 和 remediation 必須為空陣列,避免把未發生的注入或猜測的伺服器處理寫成目前發現。這是報告欄位的範圍限制,並不表示這兩頁或整站已證明安全。
第二次執行的結果如下:
| 組別 | Day 10 工具分類 | 模型保留的分類 | 必備引用 | 自動檢查 |
|---|---|---|---|---|
| 弱點頁 | confirmed_xss |
confirmed_xss |
13 項 | 通過 |
| 編碼頁 | reflected_but_not_executed |
reflected_but_not_executed |
14 項 | 通過 |
| 不反射頁 | not_reflected |
not_reflected |
12 項 | 通過 |
三份回答都使用 needs_context。編碼與不反射組的可能影響、修正建議皆為空。Day 11 的 20 個離線測試與 Day 7 的 9 個回歸測試也都通過;反向測試包含竄改原始回應雜湊、讓請求與回應不一致、偽造 DOM 屬性、改動工具分類及漏掉必備引用。
第二次的弱點組已把 parameter: q、attribute: src、dialog_message: 1 和 dom_marker_matches_token: true 引回來源;編碼組也引用了引號編碼、src 內的文字與 dom_onerror: null;不反射組引用了未反射及 /fixed.png。這些都比第一次完整。
但弱點組的「可能影響」仍用了「任意指令碼邏輯」一詞,條件裡的「事件處理常數」也不夠清楚。本次直接證明的是固定探針在這個本機頁面上執行,沒有逐一測試其他程式碼。即使它被放在 possible_impacts,我也不把這句當作已驗證的實測結果。編碼組摘要還直接顯示 quote_entity_before_onerror 等內部欄位名稱,公開前需要改成自然語句。
我把這些判讀另存為作者核對紀錄,模型的 report.json 與 response.txt 保持原樣。文章中的結論採用較窄的說法:弱點頁執行了本次固定探針;編碼頁的探針反射到 src 值,但沒有成為獨立事件屬性或執行;不反射頁的本次識別碼沒有出現在回應。
這次,我把底層工具已觀察到的結構差異完整交給模型,並要求關鍵結論能回到指定來源。HTML 屬性值是否跳脫、是否新增事件屬性,以及瀏覽器是否執行,是三層不同的證據。
第二次模型回答保住了三組技術分類,也通過更完整的引用檢查;作者核對仍指出一處措辭超過固定探針的範圍。這份本機報告不能延伸成其他屬性、JavaScript 字串、DOM 型或儲存型 XSS 的結論,更不能替真實業務系統決定風險等級。
那就…
明天見!