HTMLに属性値をエスケープする破壊的変更が導入へ
2025年5月20日、HTML仕様が更新され、mutation XSS(mXSS)脆弱性を防ぐために属性内の<および>をエスケープするようになりました。この変更は、2025年5月28日にベータチャンネルに昇格し、2025年6月24日に安定版になるChrome 138に実装されます。
本記事では、HTML属性のエスケープに関する変更がWeb開発者に与える影響や、想定される破壊的変更について説明します。変更のセキュリティ的背景は、Security Engineeringブログの関連投稿にて詳しく解説されています。
何が変わったのか
たとえば、data-content 属性に "<u>hello</u>" を持つ <div> 要素があるとします。このとき、div.outerHTML を読み取るとどうなるでしょうか?
従来は、次のようなHTMLが得られました。
<div data-content="<u>hello</u>"></div>変更後は、次のようになります。
<div data-content="<u>hello</u>"></div>以前は属性内の < や > はエスケープされませんでした。今後、これらの文字列は常にエスケープされます。
変わらないこと
今回の変更は、HTMLフラグメントが文字列としてシリアライズされるときの挙動にのみ影響します。影響を受けるのは、innerHTML や outerHTMLにアクセスするケースや、要素に対して getHTML() メソッドを呼び出すようなケースのみです。これらの操作は、既存のDOM構造を受け取り、HTML文字列を生成します。
この変更はHTMLのパース処理には影響しません。次のようなHTMLを考えてみましょう。
<div id="div1" data-content="<u>hello</u>"></div><div id="div2" data-content="<u>hello</u>"></div>どちらのdivも同じようにパースされ、div.dataset.content の結果は両方とも "<u>hello</u>" になります。
何が壊れないのか?
getAttribute、getAttributeNS、dataset、attributes など、DOM APIを用いて属性値を取得する場合、以前と同じデコードされた値、とくに< と > がデコードされた値が返されます。
以下の例では、すべての console.log が "<u>" を出力します。
<div data-content="<u>"></div>const div = document.querySelector("div");// All of the following will log "<u>"console.log(div.getAttribute("data-content"));console.log(div.dataset.content);console.log(div.attributes['data-content'].value);何が壊れる可能性があるか?
innerHTMLやouterHTMLで属性値を取得している場合
属性値の抽出に innerHTML や outerHTML を使用している場合、コードが壊れる可能性があります。たとえば次のような少し込み入った例を考えます。
<div data-content="<u>"></div>const div = div.querySelector("div");const content = div.outerHTML.match(/"([^"]+)"/)[1];console.log(content);このコードは、変更後は異なる挙動になります。以前は content は "<u>" でしたが、今後は "<u>" になります。
なお、正規表現でHTMLをパースするのは推奨されないことに注意してください。属性値を取得するには、前述のDOM APIを利用してください。
エンドツーエンドテスト
ChromiumでHTMLを生成するCI/CDパイプラインで、期待される静的なHTMLと比較するようなテストを実行している場合、属性値に < や > を含んでいるとテストが失敗する可能性があります。
これは想定された破壊的変更であり、< と > をそれぞれ < と > にエスケープした新しい期待値に更新する必要があります。
まとめ
本記事では、HTML仕様の変更により、属性内の < と > がエスケープされるようになり、一部のmutation XSSを防ぐことでセキュリティが向上することを紹介しました。
この変更は、2025年6月24日のChromium(バージョン138)とFirefox(バージョン140)ですべてのユーザーに適用されます。また、2025年9月ごろにリリース予定のSafari 26 Betaにも含まれる予定です。
もしこの変更によってウェブサイトが壊れてしまい、簡単に修正できない場合は、https://issues.chromium.org/ にバグを報告してください。
追加情報
- この変更の提案に関するもとのバグレポート
- 仕様を変更したプルリクエスト
- ChromeStatusのエントリ
- この変更のセキュリティ的背景に関するGoogle Security Engineeringブログの投稿
“HTML spec change: escaping < and > in attributes | Blog | Chrome for Developer” by Google, licensed under Creative Commons Attribution 4.0 License / translated into Japanese by ろぼいん
記事をシェア
フォローして最新情報を入手
Googleの優先ソースに追加すると、このサイトの記事をGoogleで見つけやすくなります。また、ぜひXやRSSフィードもフォローしてください。
-1.png&w=1080&q=75)
生まれた時から、母国語よりも先にJavaScriptを使っていました。ネットの海のどこにもいなくてどこにでもいます。
Webフロントエンドプログラマーとして、TypeScriptを用いたWebアプリやブラウザー拡張機能を制作。Xのシャドウバン検知ツール「Shadowban Scanner」やリンクカード復活ツール「Restore Link Card」を公開し、国内外のメディアで紹介されました。iGEM 2023ではJapan-UnitedチームのWikiを制作してGrand Prizeの獲得に貢献。ブログではXやSNSの最新ニュース、不具合の検証と対処法、フロントエンド開発の知見を発信しています。






![Gboardの[フリック入力のみ]の設定画面の開き方を示したスクリーンショット](/_next/image/?url=%2Fapi%2Fmedia%2Ffile%2Fgboard-flick-only.png&w=3840&q=75)


![[新しいXチャットへようこそ]というテキストが画面に大きく表示されており、その下には次の3つの説明が表示されている。[エンドツーエンドの暗号化:メッセージは、端末にかかわらずエンドツーエンドで暗号化されています。][最先端のプライバシー:Xを含め、他の人がメッセージを読むことはできません。][パスコードを設定:メッセージを保護するため、4桁のパスコードを設定してください。]これらの説明の下には、[パスコードを作成]という大きなボタンが配置されている](/_next/image/?url=%2Fapi%2Fmedia%2Ffile%2Fwelcome-to-new-chat.png&w=1920&q=75)
![npmのパッケージの設定画面のスクリーンショット。[Trusted Publisher]セクションの[Select your publisher]に[GitHub Actions]と[GitLab CI/CD]の2つのボタンが表示されている](/_next/image/?url=%2Fapi%2Fmedia%2Ffile%2Fnpm-trusted-publishing-settings.png&w=3840&q=75)


