Modern Frontend CVEs

対象CVE: CVE-2026-63376

[技術解説] toml-nodeのプロトタイプ汚染脆弱性(GHSA-v5mp-jgw5-2x6j)とその対策

TOMLパーサーライブラリ「toml-node」に、Node.jsアプリケーション全体に影響を及ぼす深刻なプロトタイプ汚染の脆弱性(CVE-2026-63376)が発見されました。本記事では、この脆弱性のメカニズム、影響、そして日本のフロントエンドエンジニアが取るべき対策を詳しく解説します。

はじめに:toml-nodeと今回の脆弱性概要

皆さん、こんにちは!日本のフロントエンドエンジニアの皆さんにとって、Node.js環境での開発はもはや日常でしょう。ビルドツールや設定ファイルの解析など、裏側で様々なライブラリが動いています。今回注目するのは、TOML形式のファイルをパースする人気ライブラリ「toml-node」に発見された、極めて深刻度の高いプロトタイプ汚染(Prototype Pollution)の脆弱性「GHSA-v5mp-jgw5-2x6j / CVE-2026-63376」です。この脆弱性は、悪意のあるTOML入力によって、Node.jsプロセス全体に影響を及ぼす可能性を秘めています。本記事では、その技術的な詳細と、私たちフロントエンドエンジニアが取るべき対策について深掘りしていきます。

Prototype Pollution(プロトタイプ汚染)とは?

プロトタイプ汚染とは、JavaScriptのオブジェクトがプロトタイプチェーンを通じてプロパティを継承する仕組みを悪用し、<code>Object.prototype</code>などの組み込みオブジェクトのプロトタイプに、攻撃者によって任意のプロパティを追加・変更できてしまう脆弱性です。一度<code>Object.prototype</code>が汚染されると、そのNode.jsプロセス内で作成される全てのオブジェクト(<code>Object.create(null)</code>で作成されたものを除く)が、意図しないプロパティを持つことになります。これにより、以下のような深刻な問題を引き起こす可能性があります。

・**サービス拒否(DoS)**:システムが依存する重要なプロパティを上書きし、アプリケーションをクラッシュさせる。 ・**ロジック・認証バイパス**:アプリケーションの内部ロジックや認証メカニズムを不正に操作する。 ・**リモートコード実行(RCE)**:特定の条件下では、任意のコード実行に繋がる。

CVE-2026-63376の技術的詳細:なぜtoml-nodeは汚染されたのか?

今回の脆弱性は、<code>toml.parse()</code>関数が攻撃者によって制御されたキーを<code>Object.prototype</code>に書き込んでしまうことにあります。一見すると、toml-nodeはテーブルを<code>Object.create(null)</code>で作成しているため、直接的な<code>[__proto__]</code>キーによる汚染を防いでいるように見えますが、巧妙な回避策が存在しました。

toml-nodeのコンパイラは、<code>lib/compiler.js</code>内の<code>deepRef</code>関数でテーブルパスを解決します。この関数は、キーパスの各セグメントを辿ってオブジェクトグラフをウォークしますが、ここで<code>__proto__</code>(および<code>constructor</code>、<code>prototype</code>)を通常のトラバース可能なキーとして扱ってしまいます。さらに、以下の問題が組み合わさります。

もしパスの途中にスカラー値(例えば数値<code>1</code>)が挟まっている場合、そのスカラー値のプロトタイプチェーンを辿ることが可能になります。具体的には、<code>a.b.y.__proto__.__proto__</code>のようなパスで、<code>a.b.y</code>が数値<code>1</code>を保持していた場合、最初の<code>__proto__</code>で<code>Number.prototype</code>に到達し、さらに<code>__proto__</code>を辿ることで最終的に<code>Object.prototype</code>に到達してしまいます。コンパイラが<code>Object.create(null)</code>で作成するのは「コンテナテーブル」のみであり、そこに格納される「値」自体は通常のプロトタイプチェーンを持っています。

<code>deepRef</code>関数には、既存のキーを再定義できないようにするためのガード(<code>Cannot redefine existing key</code>)が存在します。しかし、このガードはパス追跡に使われる文字列形式の不整合によって簡単に迂回されます。

コンパイラの内部では、パスの追跡に利用される<code>currentPath</code>が、配列(<code>["a","b"]</code>)と文字列(<code>"a.b"</code>)の2種類の形式で記録される箇所があります。値が代入される際のパス生成(<code>fullPath = currentPath ? currentPath + "." + keys.join(".") : keys.join(".")</code>)において、<code>currentPath</code>が配列の場合、<code>Array.toString()</code>によってカンマ区切りの文字列(例: <code>"a,b.y"</code>)に変換されて<code>valueAssignments</code>に記録されます。

一方で、<code>deepRef</code>関数内で<code>traversedPath</code>を構築する際はドット区切り(例: <code>"a.b.y"</code>)を使用します。これにより、<code>valueAssignments.has("a.b.y")</code>のチェックがミスし、ガードが機能しないため、プロトタイプ汚染が成功してしまいます。

また、テーブル配列(<code>[[a]]</code>)を使用した場合、<code>addTableArray</code>内で既存の追跡エントリが文字列プレフィックスで削除されるため、ガード状態がリセットされ、同様に<code>__proto__</code>チェーンを辿る汚染が可能になります。

実際に<code>Object.prototype</code>が汚染される様子を再現できます。<code>toml@4.1.1</code>をインストールし、以下のコードを実行してみてください。

```js const toml = require("toml"); delete Object.prototype.polluted; toml.parse(` [a.b] y = 1 [a.b.y.__proto__.__proto__] polluted = "yes" `); console.log(({}).polluted); // -> "yes" ```

```js toml.parse(` aa = 1 [[a]] [aa.__proto__.__proto__] polluted = "yes" `); console.log(({}).polluted); // -> "yes" ```

これにより、新しく作成されたオブジェクトが「polluted」プロパティを継承していることが確認できます。ネストされたオブジェクトも注入可能です。

```js toml.parse(` [a.b] y = 1 [a.b.y.__proto__.__proto__.code] val = "arbitrary" `); console.log(({}).code.val); // -> "arbitrary" ```

影響とリスク

この脆弱性の影響は非常に広範囲に及びます。以下のようなアプリケーションが危険に晒される可能性があります。

・**信頼できないTOMLドキュメントをパースするアプリケーション**:ユーザーがアップロードする設定ファイル、プロジェクトマニフェスト、マルチテナント設定、パッケージメタデータなど、攻撃者がTOMLコンテンツを操作できるあらゆる場所が対象です。

・**Node.jsプロセス全体への影響**:<code>Object.prototype</code>の汚染は、そのNode.jsプロセス内で生成される全てのオブジェクトに影響を及ぼします。これは、パースされた結果オブジェクトだけでなく、プロセス全体のセキュリティを脅かします。

・**広範な依存関係**:<code>toml</code>ライブラリは、週に約1480万回のダウンロードがあり、約1,340ものプロジェクトが直接または間接的に依存しています。<code>front-matter</code>や様々な設定ローダーなどで<code>toml</code>をパースエンジンとして使用している場合、これらのアプリケーションも同様に影響を受けます。

対策と緩和策

この深刻な脆弱性から身を守るために、以下の対策を速やかに講じましょう。

最も直接的な対策は、脆弱性が修正された最新バージョンに<code>toml-node</code>をアップデートすることです。現時点では、この脆弱性に対応したバージョンはリリースされていないようですが、監視を続け、リリースされ次第、すぐに適用してください。一般的な手順は以下の通りです。

```bash npm install toml@latest # または yarn upgrade toml ```

攻撃者がTOML入力を操作できる可能性がある場合は、パースする前に不審なキー(<code>__proto__</code>, <code>constructor</code>, <code>prototype</code>など)が含まれていないかチェックし、除去するなどのサニタイズ処理を検討してください。しかし、これは一時的な対策であり、根本的な解決にはライブラリの修正が必要です。

JavaScriptアプリケーション全体でプロトタイプ汚染に対する防御を強化するために、以下の手法を検討できます。

・**<code>Object.freeze(Object.prototype)</code>**:アプリケーションの初期段階で<code>Object.prototype</code>を凍結し、プロパティの追加・変更を防ぐ。 ・**セキュアなJSONパーサーの利用**:JSONの場合、<code>JSON.parse()</code>はデフォルトでプロトタイプ汚染を防ぐ(キーを文字列として扱うため)。TOMLでも同様にセキュアなパーサーを選定する。 ・**Linterルールの適用**:<code>eslint-plugin-no-prototype-builtins</code>のようなLinterプラグインを利用して、<code>Object.prototype</code>に直接アクセスするような危険なコードを検出する。

もし可能であれば、信頼できないTOMLファイルをパースする処理を、ネットワークやファイルシステムへのアクセスが制限されたサンドボックス環境(例: 別途DockerコンテナやWeb Workerなど)で実行することも有効な緩和策となり得ます。

まとめ

<code>toml-node</code>に発見されたプロトタイプ汚染の脆弱性(CVE-2026-63376)は、私たちが利用するオープンソースライブラリに潜む危険性を改めて認識させます。この脆弱性は、設定ファイルの取り扱いからビルドプロセスに至るまで、Node.jsアプリケーションの様々な側面に影響を及ぼす可能性があります。

フロントエンドエンジニアとして、単に美しいUIを構築するだけでなく、使用しているライブラリのセキュリティにも常に気を配ることが重要です。脆弱性情報のアンテナを張り、迅速なアップデートと防御策の導入を心がけましょう。皆さんのアプリケーションが安全であることを願っています!

← ブログ一覧に戻る