
Chrome の V8 型混同ゼロデイ CVE-2026-85046 - Array.prototype.sort のインライン化が生んだ Map の食い違い
ブラウザを起点にした攻撃と防御の総覧。
pwnの基礎からメモリ破壊の原理を学べる。
低レイヤの挙動を手で確かめるための一冊。
当サイトは Amazon.co.jp を宣伝しリンクすることで紹介料を得る手段を提供する、Amazonアソシエイト・プログラムの参加者です。価格・在庫はリンク先の最新情報をご確認ください。
ブラウザの脆弱性は「怖い」と言われがちですが、具体的に何がどう壊れているのかは説明されないまま終わることが多いものです。今回の CVE-2026-85046 は、報告者本人が技術的な解説記事を公開しているため、Chrome のゼロデイとしては珍しく根本原因まで一次情報で追えるケースになりました。
2026年9月3日、Google は Chrome の Stable チャンネルを 152.0.7977.82 に更新し、「Google is aware that an exploit for CVE-2026-85046 exists in the wild.」と明記しました。翌9月4日、CISA はこれを Known Exploited Vulnerabilities(KEV)カタログへ追加しています。2026年に入って6件目の、実際に悪用が確認された Chrome のゼロデイです。
この記事では、Chrome Releases の公式投稿、CVE レコード、NVD、KEV の JSON フィード、V8 のコミットログとソースコード、そして報告者の技術解説という確認可能な情報をもとに、何が壊れていたのか、どこまでが被害範囲なのか、いま何をすべきかを整理します。攻撃の再現手順や動く PoC は扱いません。
WARNING
この記事は2026年9月6日時点で確認できた情報にもとづいています。CVE-2026-85046 は悪用が確認済みで、KEV の是正期限は 2026-09-18 です。修正版は Chrome 152.0.7977.82(Windows / Mac は .82 または .83)です。対応判断は必ず Chrome Releases と KEV カタログで最新状態を確認したうえで行ってください。
タイムライン - 報告から30日、修正コミットから27日で公開
V8 のコミットのタイムスタンプ、CVE レコードの日時、Chrome Releases の投稿日、Microsoft Edge のリリースノート、KEV の JSON フィードから、確認できる出来事だけを並べます。
| 日時(UTC) | 出来事 | 出典 |
|---|---|---|
| 2026-04-27 07:54 | V8 に Array.prototype.sort のインライン化が再着地(コミット 66a3f1e、CL 7791329) | V8 git |
| 2026-08-04 | Salvatore Gulizia(Serotav)が Chrome へ報告、報奨金 1,000ドル | Chrome Releases |
| 2026-08-07 06:52 | 修正コミット e0562d8「Don't inline Array.prototype.sort on mixed elements kinds」が main へ | V8 git |
| 2026-09-01 07:50〜10:02 | 同じ修正が V8 のリリースブランチ 15.0(M150)/ 15.1(M151)/ 15.2(M152)へマージ | V8 git |
| 2026-09-02 | Microsoft Edge Stable 152.0.4191.62 が公開、CVE 番号を名指しして修正を告知 | Microsoft Learn |
| 2026-09-02 21:13 | CVE-2026-85046 が予約される | CVE.org |
| 2026-09-03 | Chrome Stable 152.0.7977.82/.83 公開、Chrome for Android も同日 152.0.7977.82 へ | Chrome Releases |
| 2026-09-03 19:26 | CVE レコードが PUBLISHED に(CNA は Chrome) | CVE.org |
| 2026-09-03 20:17 | NVD に登録 | NVD |
| 2026-09-04 | CISA KEV へ追加、是正期限 2026-09-18 | CISA KEV |
| 2026-09-05 04:18 | NVD のステータスが Analyzed に | NVD |
このタイムラインから読み取れることが3つあります。
1つ目。Edge のほうが Chrome より1日早く出ています。 Microsoft の Edge セキュリティリリースノートは、9月2日の Edge Stable 152.0.4191.62 について「The Chromium team reported that CVE-2026-85046 has an exploit in the wild, and this update contains a fix for it.」と書いています。Chrome Releases の投稿は9月3日です。V8 のリリースブランチへ修正がマージされたのは9月1日なので、下流のベンダーが先に出荷したという順序自体は不自然ではありません。ただし「Chrome の発表を待ってから対応を始める」運用だと、公開情報としては1日遅れることになります。
2つ目。修正は M152 だけでなく M150 / M151 にもマージされています。 V8 のリリースブランチ 15.0 と 15.1 のログには、9月1日付で [M150] / [M151] のプレフィックス付きで同じ修正が入っています。CVE レコードの affected は「152.0.7977.82 未満」と一括表記ですが、実態としてはChrome 150 系・151 系にも脆弱なコードが入っていたと読むのが自然です。
3つ目。もっと古いブランチには修正が来ていません。 V8 の 14.9 ブランチ(M149 相当)にも問題の関数 TryReduceArrayPrototypeSort は存在しますが、このブランチの最終更新は2026年7月6日で、今回の修正はマージされていません。サポートが切れた Chromium を同梱したままの製品や組込み機器は、修正を受け取れない可能性があります。
CVE-2026-85046 の基本情報
| 項目 | 内容 | 出典 |
|---|---|---|
| CVE ID | CVE-2026-85046 | CVE.org |
| CNA | Chrome(Google) | CVE.org |
| 説明 | Type confusion in V8 in Google Chrome prior to 152.0.7977.82 allowed a remote attacker to execute arbitrary code inside the sandbox via a crafted HTML page. | CVE.org / NVD |
| Chromium 側の深刻度 | High | Chrome Releases |
| CWE | CWE-843(Access of Resource Using Incompatible Type) | CVE.org |
| CVSS 3.1 | 8.8 HIGH / AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H | CISA-ADP(NVD 上は Secondary) |
| SSVC(2026-09-03) | Exploitation: active / Automatable: no / Technical Impact: total | CISA-ADP |
| KEV 追加日 | 2026-09-04(是正期限 2026-09-18、forensicTriage: No) | CISA KEV |
| ランサムウェア利用 | Unknown | CISA KEV |
| 報告者 | Salvatore Gulizia(nickname: Serotav)、2026-08-04 報告、報奨金 1,000ドル | Chrome Releases |
| Chromium issue | 542403045(サインインが必要で内容は非公開。NVD もこの参照に Permissions Required タグを付与) | issues.chromium.org / NVD |
ここで押さえておきたいのがCVSS 8.8 の出どころです。NVD のレコードを見ると、cvssMetricV31 のソースは CISA-ADP(Vulnrichment)で、type は Secondary になっています。Chrome は CNA として CVSS を付けていません。Google が公表しているのは「Chromium security severity: High」という自前の区分だけです。ベンダーが数値を出していない脆弱性でも、後段のエンリッチメントで数値が付く、という構図を知っておくと、スコアの重みづけを間違えにくくなります。
UI:R(ユーザー操作が必要)は「悪意あるページを開かせる必要がある」ことを意味します。とはいえ、広告配信網や侵害された正規サイト、あるいは iframe 経由でも成立するため、ユーザー操作の要件は実務上ほとんど障壁になりません。SSVC の Automatable: no も「大量自動化はしにくい」という意味で、標的型攻撃の抑止にはなりません。
前提知識 - V8 は配列と型をどう表現しているか
Map(hidden class)が型を決める
型混同の話に入る前に、V8 がオブジェクトをどう表現しているかを押さえます。
JavaScript のオブジェクトはプロパティを自由に追加・削除できるため、C++ の構造体のような固定レイアウトを持てません。V8 はこれをMap(hidden class とも呼ばれる)という仕組みで解決しています。すべてのヒープオブジェクトは先頭のフィールドに Map へのポインタを持ち、Map 側が「このオブジェクトはどんな型で、どのプロパティがどのオフセットにあるか」を記述します。
同じ形のオブジェクトは同じ Map を共有します。だから最適化コンパイラは「この場所に来るオブジェクトの Map はこれだ」と仮定して、プロパティアクセスを固定オフセットのメモリ読み出しへ落とせます。仮定が崩れないよう、実行時には Map をチェックするガード(CheckMaps)を挿入し、外れたら最適化コードを捨てて(デオプティマイズ)インタプリタへ戻ります。
型混同とは、この「Map が示す型」と「実際にメモリに入っている値」が食い違う状態のことです。CWE-843 の定義そのものです。V8 にとってこれが致命的なのは、Map が単なるメタデータではなくメモリ解釈のルールそのものだからです。
ElementsKind の遷移格子
配列の要素については、Map に加えて ElementsKind という区分があります。V8 のソース src/objects/elements-kind.h から、先頭部分を引用します。
// v8/src/objects/elements-kind.h
enum ElementsKind : uint8_t {
// The "fast" kind for elements that only contain SMI values. Must be first
// to make it possible to efficiently check maps for this kind.
PACKED_SMI_ELEMENTS,
HOLEY_SMI_ELEMENTS,
// The "fast" kind for tagged values. Must be second to make it possible to
// efficiently check maps for this and the PACKED_SMI_ELEMENTS kind
// together at once.
PACKED_ELEMENTS,
HOLEY_ELEMENTS,
// The "fast" kind for unwrapped, non-tagged double values.
PACKED_DOUBLE_ELEMENTS,
HOLEY_DOUBLE_ELEMENTS,
// ...主要な6種類の意味は次のとおりです。
| ElementsKind | 中身 | バッキングストア |
|---|---|---|
PACKED_SMI_ELEMENTS | 小整数(Smi)のみ、穴なし | タグ付きスロットの FixedArray |
HOLEY_SMI_ELEMENTS | 小整数のみ、穴あり | タグ付きスロットの FixedArray |
PACKED_DOUBLE_ELEMENTS | 浮動小数点数、穴なし | 生の double を並べた FixedDoubleArray |
HOLEY_DOUBLE_ELEMENTS | 浮動小数点数、穴あり | FixedDoubleArray |
PACKED_ELEMENTS | 任意の値(オブジェクト参照を含む)、穴なし | タグ付きスロットの FixedArray |
HOLEY_ELEMENTS | 任意の値、穴あり | タグ付きスロットの FixedArray |
V8 公式ブログの解説記事「Elements kinds in V8」(Mathias Bynens)は、これらが格子(lattice)を成し、遷移は一方向にしか進まないと説明しています。原文は「It's only possible to transition downwards through the lattice.」です。整数だけの配列に浮動小数点数を1つ入れれば double 側へ、オブジェクトを1つ入れれば汎用側へ落ちます。一度落ちたら、あとで値を戻しても元の種類には帰ってきません。 V8 は全部で21種類の elements kind を区別している、とも同記事は述べています。
ここで重要なのが、PACKED_SMI_ELEMENTS と PACKED_ELEMENTS はバッキングストアの物理レイアウトが同じという点です。どちらもタグ付きスロットが並んだ FixedArray で、違うのは「中身が Smi だけだと保証されているか」だけです。この「レイアウトは同じだが意味が違う」ペアが、今回の事件の舞台になります。
何が壊れていたのか - sort のインライン化と comparefn の副作用
報告者 Salvatore Gulizia は、自身のブログ「When Sorting Leads To Confusion」で根本原因を次のように要約しています。
a v8 bug in the compilers that leads to an array containing PACKED_ELEMENTS to receive the map PACKED_SMI_ELEMENTS, this can be turned into arb r/w on the js heap. The bug was present in both maglev and turbofan
そして V8 側の修正コミットのメッセージが、同じ内容を V8 開発者の言葉で説明しています。
[compiler] Don't inline Array.prototype.sort on mixed elements kinds
CanInlineArrayIteratingBuiltin unions the receiver elements kinds, so
polymorphic feedback yields a kind that no single receiver need have:
PACKED_SMI and PACKED union to PACKED_ELEMENTS. That is fine for the
iterating builtins, which only read the receiver, but the inlined sort
snapshots the elements, runs comparefn, and copies the snapshot back
specialized on the union kind.
A comparefn can narrow the live receiver to another kind in the map set
(a.fill(0) turns PACKED_ELEMENTS into PACKED_SMI_ELEMENTS). The
post-callback check accepts that map because it is in the original set,
and the copy-back then stores the snapshotted HeapObjects into a
Smi-elements array. Smi consumers of the resulting array read those
HeapObjects as Smis and move them without write barriers.(引用中の集合表記は MDX の都合で書き換えています。原文はコミット e0562d87ad9c17042b581582c99237d798572e67 を参照してください。)
順を追って分解します。
ステップ1 - sort をインライン化する最適化が入った
2026年4月、V8 に Array.prototype.sort を最適化コンパイラ内でインライン展開する変更が入りました。コミットの説明は次のとおりです。
For PACKED arrays with a provided comparefn and
length <= 16, replace the sort call with an inline insertion sort, avoiding the builtin-JS transition overhead on every comparefn invocation inside TimSort.
要は、要素数16以下で比較関数が与えられた packed 配列については、TimSort の組込み実装を呼ばずに挿入ソートをその場に展開するという高速化です。比較関数を呼ぶたびに組込みと JS のあいだを行き来するコストを避けられます。Maglev と TurboFan の両方に実装されました。
生成されるコードの骨格は、報告者の記事によれば次のような形です。
checkReceiverMaps();
temp = copy(receiver.elements); // 要素のスナップショットを取る
insertionSort(temp, comparefn); // 一時配列の上でソートする
checkReceiverMapsAndLength(); // 比較関数の副作用を検査する
copy(temp, receiver.elements); // 結果を書き戻す一時配列を経由するのは、仕様上の要請でもあります。ECMA-262 の sort は要素のスナップショットに対して比較を行うと定義されており、比較関数が元の配列を書き換えてもソート結果には影響しないようにしなければなりません。
ステップ2 - ガードが「変化していないこと」を確認していなかった
問題は書き戻し直前のチェックです。V8 のコード中のコメントは「comparefn side effects may have changed the receiver's map or length. Check once here before the copy-back」と書いており、意図としては正しいものでした。
しかし実装は、現在の Map がループ開始前に記録した Map 集合のいずれかに含まれているかを確認するだけでした。報告者の記事の表現を借りれば、「The code doesn't check if the map changed, it simply checks that the current array map is any of the maps in receiver_maps_before_loop.」です。
ここで効いてくるのが、コンパイラのフィードバックが多相(polymorphic)だった場合です。同じ関数を PACKED_SMI_ELEMENTS の配列と PACKED_ELEMENTS の配列の両方で繰り返し呼ぶと、コンパイラは両方の Map を候補集合に持ちます。そして2つの ElementsKind の和を取ると PACKED_ELEMENTS になるため、書き戻しは汎用要素として特殊化されます。一方でチェックは集合への所属しか見ないので、実行中に PACKED_ELEMENTS から PACKED_SMI_ELEMENTS へ切り替わってもチェックを通過してしまいます。
ステップ3 - 一方向のはずの遷移を逆走させる fill
「ElementsKind の遷移は一方向」だったはずでは、と思うところです。ここで使われるのが Array.prototype.fill です。V8 の組込み実装 src/builtins/builtins-array.cc には、全要素を置き換えるケースについて次のコメントがあります。
// v8/src/builtins/builtins-array.cc
bool is_replacing_all_elements =
(start == 0 && end == Object::NumberValue(array->length()));
bool did_transition_map = false;
if (is_replacing_all_elements) {
// For the case where we are replacing all elements, we can migrate the
// map backwards in the elements kind chain and ignore the current
// contents of the elements array.全要素を上書きするなら古い値は1つも残らないので、V8 は elements kind の連鎖を意図的に逆走させて、新しい値に最適な種類へ Map を張り替えます。PACKED_ELEMENTS の配列を Smi で全部埋めれば PACKED_SMI_ELEMENTS になります。そしてバッキングストアはどちらもタグ付き FixedArray なので、確保し直す必要すらありません。
つまり、比較関数の中で対象配列に対して fill を呼ぶだけで、ガードをすり抜ける Map の切り替えが成立します。結果として、中身はオブジェクトへのポインタなのに、Map は「中身は Smi です」と主張している配列が出来上がります。これが型混同です。
型混同はなぜ「任意の読み書き」になるのか
型混同そのものはクラッシュを起こさないこともあります。ここから先が、攻撃者にとっての価値です。
アドレス漏洩(addrof)
Map が Smi 配列だと言っているので、Map に依存する処理はスロットの中身を Smi として解釈します。V8 の Smi はポインタと同じ64ビットスロットに入っており、下位ビットのタグで区別されます。したがって配列を文字列化するような Map 依存の経路を通すと、オブジェクトのポインタが整数として出てきます。ASLR の効果を打ち消し、任意の JavaScript オブジェクトのヒープ上のアドレスを知るための素材が手に入るわけです。
書き込みバリアの省略
より深刻なのがこちらです。V8 の世代別 GC は、古い世代のオブジェクトから新しい世代への参照が書き込まれたことを記録するために書き込みバリア(write barrier)を使います。参照を書くたびにバリア用のコードが走り、GC が後で追跡できるようリメンバードセットへ登録します。
ところが今回の混同状態では、V8 はその配列を「Smi しか入っていない配列」だと思い込んでいます。Smi は参照ではないので、書き込みバリアは不要だと判断され、生成されません。 この状態でスロットの内容を移動させると、実体はポインタなのに GC の記録が残らないという不整合が生まれます。報告者は、要素をずらす操作(unshift のような、配列の容量に余裕があれば再確保なしで全要素をシフトする操作)を使ってこれを起こしたと説明しています。
GC が把握していない参照が生まれると、オブジェクトの生死判定や移動処理が破綻し、攻撃者が中身を制御できる偽のオブジェクトを作り出す(fakeobj)ところまで到達します。addrof と fakeobj が揃えば、あとは V8 ヒープ内の任意アドレス読み書きへ組み上げるのが定石です。CVE の説明文にある「execute arbitrary code inside the sandbox」は、この状態を指しています。
NOTE
型混同がなぜ強力かというと、1回のバグでメモリ破壊の「原始的な道具」が手に入るからです。バッファオーバーフローのように「何バイト書けるか」を数える必要がなく、言語ランタイムが持つ型の前提そのものを裏返せます。V8 の攻撃面としてこの種のバグが繰り返し使われるのは、そのためです。
「サンドボックス内での任意コード実行」はどこまでの被害か
CVE の説明文にある「inside the sandbox」という限定は、読み飛ばしてはいけない部分です。Chrome には防御層が2つあります。
1つ目は V8 サンドボックスです。V8 公式ブログの解説記事によれば、その脅威モデルは「an attacker can read and write arbitrarily inside the V8 Sandbox」を前提に置き、目的は「prevent memory corruption outside of the sandbox」だとされています。生ポインタや64ビットのサイズを、サンドボックス内オフセットや外部ポインタテーブル経由の間接参照に置き換えることで、V8 ヒープの破壊がプロセスの他の領域へ波及しないようにする設計です。オーバーヘッドは典型的なワークロードで「around 1% or less」とされ、64ビット版 Chrome では既定で有効です。
重要なのは、V8 サンドボックスは V8 ヒープ内部の破壊そのものは防がないことです。同記事は、V8 で見つかり悪用される脆弱性のほぼすべてがヒープ破壊に至ることを前提としたうえで、攻撃者はさらに「a V8 Sandbox bypass」という別の脆弱性を必要とすると説明しています。
2つ目はレンダラプロセスのサンドボックスとサイト分離です。V8 サンドボックスを破ってレンダラプロセス全体を掌握できたとしても、そのプロセスは OS レベルのサンドボックスに閉じ込められており、さらにサイト分離によって別オリジンのデータは原則として別プロセスに置かれています。ここから先へ進むには、もう1つサンドボックスエスケープが必要です。
したがって、CVE-2026-85046 単体で成立するのは「悪意あるページを開いた結果、そのページのレンダラプロセスの V8 ヒープを攻撃者が自由に操作できる」ところまで、というのが公開情報から言える範囲です。実際の攻撃キャンペーンで何と連鎖されていたかについて、Google は「we will retain restrictions」の方針どおり詳細を公表しておらず、執筆時点では未確認です。
とはいえ、これを理由に優先度を下げるべきではありません。理由は3つあります。
- 連鎖の相方となるサンドボックスエスケープは、n-day も含めれば流通している。報告者自身も「I chained this bug with an n-day sandbox escape」と書いています
- V8 ヒープを掌握された時点で、そのページのオリジンにおける機密(セッション、フォーム入力、表示中のデータ)は守れない
- 「in the wild」と Google が言う以上、実運用の攻撃者は連鎖を完成させている前提で考えるのが安全側
報告経路についての注意 - v8CTF と in-the-wild
もう1つ、記録として書いておく必要があるのが報告経路です。報告者は自身の解説記事で「I chained this bug with an n-day sandbox escape and flagged the v8CTF.」と述べています。v8CTF は Google の VRP 傘下で運営されているプログラムで、公式ルールによればGoogle のインフラ上に配備された V8 を実際に攻略してフラグを取得すると報酬が支払われる仕組みです。0-day を用いる場合は先に Chrome VRP へ報告することが求められます。
一方、Chrome Releases の投稿にあるのは「Google is aware that an exploit for CVE-2026-85046 exists in the wild.」という定型文です。この2つの事実の関係、すなわち Google の言う「in the wild」が第三者による実攻撃を指すのか否かについて、Google は説明を公表していません。 報道各社もこの点には踏み込んでいません。ここは未確認とし、本記事では推測を述べません。
対応方針としては影響しません。KEV へ追加された以上、CISA の判断としては悪用が確認されている扱いであり、やることは「今すぐ更新する」で変わらないからです。
影響範囲 - Chrome だけの話ではない
V8 は Chromium の一部であり、Chromium は多数の製品に組み込まれています。KEV の shortDescription も、この点を明示しています。
Google Chromium V8 contains a type confusion vulnerability that allows a remote attacker to execute arbitrary code inside the sandbox via a crafted HTML page. This vulnerability could affect multiple web browsers that utilize Chromium, including, but not limited to, Google Chrome, Microsoft Edge, and Opera.
執筆時点で一次情報から確認できた、各製品の状況を整理します。
| 製品 | 修正版 | 確認状況 |
|---|---|---|
| Google Chrome(Windows / Mac) | 152.0.7977.82 または .83 | Chrome Releases(2026-09-03)で確認 |
| Google Chrome(Linux) | 152.0.7977.82 | Chrome Releases(2026-09-03)で確認 |
| Chrome for Android | 152.0.7977.82 | Chrome Releases(2026-09-03)で確認 |
| Microsoft Edge(Stable) | 152.0.4191.62 | Edge セキュリティリリースノート(2026-09-02)が CVE を名指し |
| Brave(Desktop) | v1.94.121(Chromium 152.0.7977.83 を取り込み) | Brave リリースノートで確認。CVE の名指しはなし |
| Opera / Vivaldi | 該当版を特定できず | 執筆時点で未確認 |
| Electron | 44.2.0 / 43.6.0 / 42.11.2(2026-09-04 公開) | 「Backported fixes from upstream ANGLE, Chromium, Skia and V8」とあるが CVE 番号の記載なし。該当修正の有無は未確認 |
Electron については補足が必要です。Electron 44 系が Chromium 152 系に対応しており、9月4日にリリースされた 44.2.0 / 43.6.0 / 42.11.2 のリリースノートには上流からのバックポートが記載されています。しかしリリースノートに CVE-2026-85046 の明示的な記載はなく、当該修正が含まれるかは執筆時点で未確認です。Electron 製アプリでリモートコンテンツを描画している場合は、自分でリリースノートと Chromium バージョンを突き合わせて判断してください。
CEF(Chromium Embedded Framework)を使っている製品についても同様です。ブラウザの更新だけを管理していると、Chromium を内包したデスクトップアプリの棚卸しが丸ごと抜け落ちます。 WebAssembly の実行環境としての Chromium の広がりについてはWebAssemblyがブラウザの外へ出た2026年でも触れています。
いますぐやること - 更新とその確認
手元の Chrome を更新する
chrome://settings/help(Chrome メニューの「ヘルプ」から「Google Chrome について」)を開くと、更新の確認が自動で走ります。ここで最も見落とされるのが再起動です。更新のダウンロードが終わっても、ブラウザを再起動するまで古いバイナリが動き続けます。ページの右上に「再起動」ボタンが出ていたら、それを押すまで対策は完了していません。
コマンドラインからバージョンを確認する方法も挙げておきます。
# macOS
defaults read "/Applications/Google Chrome.app/Contents/Info.plist" CFBundleShortVersionString
# Linux(ディストリビューションのパッケージ名に読み替えてください)
google-chrome --version
# Windows(PowerShell)
(Get-Item "C:\Program Files\Google\Chrome\Application\chrome.exe").VersionInfo.ProductVersionWindows で Google Update が把握しているバージョンを見るなら、レジストリを直接読む方法もあります。
reg query "HKLM\SOFTWARE\WOW6432Node\Google\Update\Clients\{8A69D345-D564-463c-AFF1-A69D9E530F96}" /v pv更新チェックリスト
- Chrome を 152.0.7977.82 以上にし、再起動まで完了させた
- Chrome for Android を 152.0.7977.82 以上にした
- Microsoft Edge を 152.0.4191.62 以上にした
- Brave / Opera / Vivaldi など、社内で使われている Chromium 系ブラウザを洗い出して更新した
- Chromium を同梱するデスクトップアプリ(Electron / CEF 製)を棚卸しし、ベンダーの更新状況を確認した
- キオスク端末、デジタルサイネージ、検査装置など手動更新の Chromiumがないか確認した
- 長期間再起動されていない共用端末・仮想デスクトップの再起動を計画した
- 更新が届かないサポート切れ端末の利用継続可否を判断した
組織で更新を強制する
Chrome の管理ポリシーには、更新後の再起動を促す仕組みがあります。Chromium のポリシー定義から確認できる範囲で挙げます。
| ポリシー | 効果 |
|---|---|
RelaunchNotification | 値 1 で「再起動を推奨」の通知、値 2 で「一定期間後に強制的に再起動する」旨の通知を繰り返し表示 |
RelaunchNotificationPeriod | 上記の猶予期間。既定は Chrome で7日、ChromeOS で4日 |
RelaunchWindow | 強制再起動を行う時間帯を指定し、業務時間中の再起動を避ける |
RelaunchNotification を 2 に設定した場合、猶予期間が過ぎるとブラウザは強制的に再起動されます。ポリシー定義には「The user's session is restored following the relaunch/restart.」とあり、セッションは復元されるため、業務影響は限定的です。緊急時にはこの値を一時的に 2 にし、RelaunchNotificationPeriod を短縮するのが実効的です。
Windows で Google Update 側にバージョン固定(TargetVersionPrefix)を入れている組織は、その固定が修正版より前を指していないかを真っ先に確認してください。互換性検証のために古いバージョンへピン留めしたまま忘れている、というのはよくある事故です。
更新までのつなぎとしての緩和策
今回のバグは最適化コンパイラ(Maglev / TurboFan)が生成するインライン化コードの中にあります。修正コミットのタイトルが「Don't inline Array.prototype.sort ...」であることからも明らかです。したがって、V8 の高度な最適化を無効化すれば、この経路そのものが消えます。
Chrome にはこれを制御するポリシーがあります。DefaultJavaScriptOptimizerSetting は、ポリシー定義の説明によれば「whether Google Chrome will run the v8 JavaScript engine with more advanced JavaScript optimizations enabled」を制御し、値 2(BlockJavaScriptOptimizer)で無効化します。Chrome 133 以降でサポートされ、JavaScriptOptimizerAllowedForSites / JavaScriptOptimizerBlockedForSites によるサイト単位の上書きも可能です。
{
"DefaultJavaScriptOptimizerSetting": 2,
"JavaScriptOptimizerAllowedForSites": ["[*.]example.co.jp"]
}WARNING
この緩和策は更新の代わりにはなりません。ポリシー定義自体が「may render web content more slowly」と警告しているとおり、JavaScript の実行性能は明確に落ちます。また、この設定が CVE-2026-85046 を確実に無効化するとは Google も CISA も述べていません。バグが最適化コンパイラ内にあるという事実から導いた推論であり、ベンダーが検証した緩和策ではない点にご注意ください。すぐに更新できない特殊端末に対する時間稼ぎとして検討する程度に留めるべきです。
検知と調査 - 何ができて、何ができないか
正直に書くと、クライアント側でこの脆弱性の悪用を後から検知するのは非常に困難です。攻撃はブラウザのプロセス内で完結し、ネットワーク上には「JavaScript を含む HTML の取得」しか現れません。それでも、できることはあります。
1. バージョンの棚卸しを証跡として残す。 エンドポイント管理ツールやインベントリで、修正版より前の Chrome / Edge が残っている端末を列挙します。この一覧は、後日インシデントが疑われたときに「どの端末が露出期間にあったか」を示す唯一の資料になります。
2. レンダラのクラッシュを見る。 エクスプロイトは安定するまでにクラッシュを伴うことがあります。Chrome のクラッシュレポートを企業側で収集している場合、露出期間中のレンダラプロセスのクラッシュ増加は調査の入口になります。ただし通常のバグでもクラッシュは起きるので、これ単独では判断材料になりません。
3. 「その後」を探す。 ブラウザの侵害が価値を持つのは、そこから何かが起きたときです。露出期間中の、認証情報の異常な利用、セッションの不審な再利用、想定外の端末からのアクセス、拡張機能の追加。ブラウザそのものより、その先の認証基盤のログのほうが痕跡が残ります。
4. 調査の限界を明示する。 ブラウザ内部の挙動を記録していなかった期間について書けるのは、「痕跡がない」ではなく「確認できない」です。報告書の書き方はここを曖昧にしないでください。この原則は2026年 日本のセキュリティインシデントまとめで扱った各事例でも、公表の質を分ける要素になっていました。
なお、Content Security Policy はこの種の脆弱性に対する直接の防御にはなりません。CSP はスクリプトの出所を制限する仕組みであって、許可されたスクリプトがエンジンのバグを踏むことは止められないからです。とはいえ、悪意あるスクリプトが差し込まれる経路そのものを減らす効果はあるので、CSPの設計と運用は引き続き有効な多層防御の一枚です。
2026年の Chrome ゼロデイ6件を並べる
KEV の JSON フィードから、2026年に KEV へ追加された Google 製品の脆弱性を抽出すると、ちょうど6件になります。「6件目」という表現の根拠として、これが最も確認しやすい一次情報です。
| CVE | コンポーネント | 種別(CVE の説明より) | KEV 追加日 | 是正期限 |
|---|---|---|---|---|
| CVE-2026-2441 | CSS | Use after free | 2026-02-17 | 2026-03-10 |
| CVE-2026-3909 | Skia | Out of bounds write | 2026-03-13 | 2026-03-27 |
| CVE-2026-3910 | V8 | Inappropriate implementation | 2026-03-13 | 2026-03-27 |
| CVE-2026-5281 | Dawn | Use after free(レンダラ侵害が前提) | 2026-04-01 | 2026-04-15 |
| CVE-2026-11645 | V8 | Out of bounds read and write | 2026-06-09 | 2026-06-23 |
| CVE-2026-85046 | V8 | Type confusion | 2026-09-04 | 2026-09-18 |
6件のうち4件が V8です。残りはグラフィックス関連(Skia、Dawn)とレンダリング(CSS)で、いずれも攻撃者が中身を完全に制御できる入力を、高度に最適化されたネイティブコードが処理する場所という共通点があります。JIT コンパイラは、性能のために型の仮定を積み上げる仕組みであり、その仮定を1つ崩せば型混同が生まれます。原理的に攻撃面が広いのです。
Chrome の脆弱性報告が2026年に入って急増している背景については2026年のChromeで急増したAI関連セキュリティバグでも扱いました。今回の同時修正12件のうち1件(CVE-2026-85045、V8 の競合状態)は XBOW の Brendan Dolan-Gavitt による報告で、自動探索の成果がすでに Chrome のリリースノートに載り始めていることも読み取れます。
教訓 - 最適化は「前提の束」を増やす
今回の件から一般化できることを3つ挙げます。
1つ目は、「集合に含まれるか」と「変化していないか」は別の検査だ、ということです。 修正前のコードは、Map が元の候補集合に含まれることを確認していました。意図は「比較関数の副作用で壊されていないこと」の確認です。しかし多相な候補集合では、集合の中で移動するだけでチェックを通過できてしまいます。同じ種類の間違いは、状態遷移をバリデーションする一般のコードにも現れます。許可リストへの所属を確認して満足せず、「検査した時点の値と、使う時点の値が同一か」まで見る必要がある場面がある、ということです。TOCTOU(検査時と使用時の不整合)の親戚です。
2つ目は、最適化は仮定を増やし、仮定は攻撃面になる、ということです。 インライン化された sort は、要素数、比較関数の有無、Map の集合、elements kind という複数の前提の上に成り立っていました。前提が4つあれば、破るべき箇所も4つあります。しかも今回のように複数の前提を統合する処理(和を取る処理)があると、個々には正しい仮定の組み合わせが誤りを生みます。JIT の最適化を追加するたびに検証すべき組み合わせが増えるという構造は、ガベージコレクションの仕組みで扱った GC の書き込みバリアと同じで、性能と安全性のトレードオフが最も鋭く出る領域です。
3つ目は、更新の「最後の一歩」を運用に組み込むことです。 Chrome の自動更新は優秀ですが、再起動しない限り新しいバイナリは動きません。タブを大量に開いたまま何週間も再起動しないユーザーは珍しくなく、仮想デスクトップや共用端末ではさらに顕著です。KEV の是正期限が14日と設定されているのは、パッチ配布の時間ではなく組織内に浸透させる時間を見込んだ数字だと考えるべきです。今回、Edge が Chrome より1日早く出荷していたことも含め、「ベンダーがいつ出したか」と「自組織でいつ有効になったか」は別の指標として管理する必要があります。
まとめ
- CVE-2026-85046 は V8 の型混同(CWE-843)。
PACKED_ELEMENTSの配列がPACKED_SMI_ELEMENTSの Map を持つ状態を作れる - 原因は
Array.prototype.sortのインライン化。多相フィードバックで elements kind の和を取ったうえ、書き戻し前の Map チェックが「集合への所属」しか見ていなかった - 比較関数の中で
fillを呼ぶと、本来一方向のはずの elements kind 遷移を逆走させられる。バッキングストアが同じ FixedArray なので再確保も起きない - 混同状態では書き込みバリアが省略されるため、GC が把握しない参照が生まれ、fakeobj から任意読み書きへ到達する
- 修正版はChrome 152.0.7977.82(Windows / Mac は .82 または .83)。再起動するまで有効にならない
- CVSS 3.1 は 8.8 HIGH だが、これはCISA-ADP が付けた Secondary スコア。Chrome は CNA として CVSS を出しておらず、公式には「Chromium security severity: High」のみ
- 2026-09-04 に CISA KEV 追加、是正期限 2026-09-18。SSVC は Exploitation: active / Automatable: no / Technical Impact: total
- 修正は V8 のM150 / M151 / M152 の各ブランチへ 2026-09-01 にマージ済み。CVE 記載は「152.0.7977.82 未満」の一括表記だが、150 系・151 系にも脆弱なコードが存在した
- Edge は 2026-09-02 に 152.0.4191.62 で先行出荷、Brave は v1.94.121 で Chromium 152.0.7977.83 を取り込み。Opera / Vivaldi の該当版は未確認
- Electron のリリースノートに CVE 番号の記載はなく、取り込み状況は未確認。Chromium 同梱アプリの棚卸しが必要
- 「inside the sandbox」は V8 サンドボックス内部を指す。プロセス外へ出るには別途サンドボックスバイパスが必要だが、n-day を含めれば連鎖の相方は存在する
- 報告者は v8CTF での攻略にも同バグを使ったと述べている。Google の言う「in the wild」との関係は未確認
- 更新強制には
RelaunchNotificationとRelaunchNotificationPeriod。時間稼ぎとしてのDefaultJavaScriptOptimizerSettingの無効化はベンダー検証済みの緩和策ではない - 2026年に KEV 追加された Chrome 系ゼロデイは6件。うち4件が V8
ブラウザは、攻撃者が中身を100パーセント制御できる入力を、毎日何億回も処理し続けているソフトウェアです。JIT コンパイラという最も複雑な部分が繰り返し狙われるのは、必然と言っていいでしょう。仮想メモリやポインタの扱いといった土台の話は仮想メモリとページングの仕組みでも整理しています。まずは chrome://settings/help を開いて、再起動ボタンが出ていないか確認するところから始めてください。
参考リンク
- Chrome Releases: Stable Channel Update for Desktop(2026-09-03)
- Chrome Releases: Chrome for Android Update(2026-09-03)
- CVE.org: CVE-2026-85046
- NVD: CVE-2026-85046
- CISA: CISA Adds One Known Exploited Vulnerability to Catalog(2026-09-04)
- CISA: Known Exploited Vulnerabilities Catalog(CVE-2026-85046)
- CISA: KEV JSON フィード
- CISA: BOD 26-04 Prioritizing Security Updates Based on Risk
- Chromium issue 542403045(サインインが必要)
- V8: 修正コミット e0562d8「Don't inline Array.prototype.sort on mixed elements kinds」
- V8: インライン化を導入したコミット 66a3f1e
- V8: src/objects/elements-kind.h
- V8: src/builtins/builtins-array.cc
- V8: src/maglev/maglev-graph-builder.cc
- v8.dev: Elements kinds in V8
- v8.dev: The V8 Sandbox
- v8.dev: Maglev - V8's Fastest Optimizing JIT
- v8.dev: TurboFan のドキュメント
- Serotav: When Sorting Leads To Confusion(報告者による解説)
- Google: v8CTF のルール
- Microsoft Learn: Microsoft Edge セキュリティ更新のリリースノート
- MSRC: CVE-2026-85046
- Brave: Release Notes v1.94.121
- Electron: v44.2.0 リリースノート
- Electron: リリースタイムライン
- Chromium: RelaunchNotification ポリシー定義
- Chromium: DefaultJavaScriptOptimizerSetting ポリシー定義
- Chrome Enterprise ポリシー一覧
- Chromium: Site Isolation
- Chromium: Memory safety
- CWE-843: Access of Resource Using Incompatible Type
- MDN: Array.prototype.sort()
- Help Net Security: Google patches actively exploited Chrome zero-day
- The Hacker News: Google Releases Chrome Update to Patch Actively Exploited V8 Zero-Day
- Security Affairs: Google fixes the sixth actively exploited Chrome zero-day of 2026
- 2026年のChromeで急増したAI関連セキュリティバグ(当ブログ)
- Starlette の Host ヘッダ検証欠如 CVE-2026-48710(当ブログ)
- ガベージコレクションの仕組み(当ブログ)
- 仮想メモリとページングの仕組み(当ブログ)
- Content Security Policy の設計と運用(当ブログ)
- WebAssemblyがブラウザの外へ出た2026年(当ブログ)
- 2026年 日本のセキュリティインシデントまとめ(当ブログ)


