HTML規格修補XML編碼偵測漏洞,搜尋範圍收斂回宣告本身
WHATWG HTML Standard(GitHub commit)· 2026-09-21
WHATWG 為 HTML 規格裡的「XML 編碼偵測」演算法補上一個邊界條件:往後尋找 encoding屬性時,搜尋動作必須在 xmlDeclarationEnd 之前結束,不能再無限延伸到宣告結束之後的任意內容。這項修改由 Domenic Denicola 與 codex 共同提交、annevk 完成合併,commit 編號為 24434a0,時間是 2026 年 9 月 21 日。它修正的是編碼偵測演算法本身一個存在已久卻沒被抓到的邏輯漏洞。
背景
瀏覽器解析 text/html 位元組流時,會先做一輪編碼偵測(prescan),如果開頭看起來像 XML 宣告(<?xml ... ?>),就會嘗試從裡面找出 encoding="..." 屬性,藉此決定整份文件要用哪種字元編碼解讀。演算法原本就定義了一個叫 xmlDeclarationEnd 的變數,用來標記宣告本體的結尾位置。
問題在於,這個變數只是被定義出來,卻從未真的拿去限制搜尋範圍。對應到 issue #6939 裡的說明,一段像 <?xml /> encoding="windows-1252"> 這樣的畸形宣告,宣告本身其實在 /> 就已經結束,但舊演算法仍會繼續往後掃,掃到宣告外面那段 encoding="windows-1252",並誤把它當成文件編碼。也就是說,宣告外的文字也能左右整份文件的字元編碼判定,這與規格文字描述的「只看宣告本身」明顯不符。
核心改動
這次修改只動了兩行文字,把原本沒有上界的搜尋條件,補上「必須早於 xmlDeclarationEnd」這個限制:
- after the current encodingPosition. If there is no such sequence, then return
- failure.
+ after the current encodingPosition and before xmlDeclarationEnd. If there is
+ no such sequence, then return failure.修改前,演算法對「尋找 encoding 這串位元組」的敘述完全沒有終點,等於允許搜尋一路穿越宣告結尾,落到後面的任意 HTML 內容裡;修改後,同一段搜尋被明確釘死在 xmlDeclarationEnd 之前。commit message 特別點名,這個收斂後的行為才真正對得上 Chromium、Gecko、WebKit 三大引擎現行的實作,換句話說,三大引擎其實早就沒有這個漏洞,錯的一直是規格文字本身。
影響範圍
由於三大既有引擎的實作本來就沒有這個問題,這次修正不會改變 Chrome、Firefox、Safari 使用者看到的行為。真正受影響的是依照規格文字從零打造 HTML 解析器的團隊,例如 Servo、Ladybird 之類的新興引擎維護者——若他們照著舊版規格逐字實作,就會複製出「宣告外文字也能改變編碼」這個行為,形成編碼混淆型注入的風險:攻擊者只要在宣告後面塞入偽裝成 encoding= 的字串,就有機會誘使解析器切到某種可以讓特定位元組串重新解讀成 <script> 之類標籤的編碼。
對這些解析器維護者而言,需要做的事很單純:重新檢查自家「編碼偵測」或「prescan」實作裡,尋找 encoding 屬性的迴圈是否有正確參照 xmlDeclarationEnd 當作上界,並補一筆針對 <?xml /> encoding="..." 這類畸形宣告的回歸測試。對規格維護者與 WPT(Web Platform Tests)貢獻者而言,也值得順手確認測試套件裡是否已經涵蓋這個邊界情況,避免下一個新引擎重蹈覆轍。