brace-expansion: `parseCommaParts()`における制御不能な再帰によるDoS攻撃(スタックオーバーフロー)
### 概要
`parseCommaParts()`関数は、ネイティブスタックを枯渇させ、プロセスをクラッシュさせる可能性があります。この問題を発生させる方法は2つあり、どちらも単一の信頼できないパターン文字列から到達可能です。
これは、CVE-2026-14257 / GHSA-mh99-v99m-4gvgに対する解析側の対応です。その修正では、`expand_()`関数が反復処理されるようにされ、スタック深度が一定であるという保証が加えられましたが、`parseCommaParts()`関数は再帰的な構造であったため、この保証は2つの解析パスのうちの1つにしか適用されませんでした。
### ベクター1 - `post`における無制限な再帰
`parseCommaParts()`関数は、文字列の残りの部分に対して、中括弧グループごとに1回ずつ再帰的に処理を行います。
```js
const postParts = parseCommaParts(post); // 無制限
```
多くのコンマで区切られたグループを含む中括弧グループは、グループごとに1つの再帰レベルを引き起こします。
```js
expand('{' + '{a},'.repeat(7000) + 'b}');
// RangeError: Maximum call stack size exceeded
```
Node 24では、約7,300回の繰り返し(約29 KBの入力)でこのエラーが発生します。Node 18では、約6,300回(25 KB)。この閾値は、影響を受けるすべてのバージョンで同じです。
### ベクター2 - 無制限の配列を使用した`push.apply`
再帰が削除された場合でも、`parseCommaParts()`関数は、配列全体を引数リストに展開します。
```js
p.push.apply(p, postParts);
parts.push.apply(parts, p);
```
`Function.prototype.apply`は、スタック上に要素ごとに1つの引数を配置するため、単一の大きな配列がスタックをオーバーフローさせます。この問題は**再帰の深さに依存しません**。以下のコードは、再帰深度が正確に1になるように設計されています。
```js
expand('{{x},' + 'a,'.repeat(125000) + 'b}');
// RangeError: Maximum call stack size exceeded
```
閾値は約124,300回の繰り返し(約249 KB)。このベクターは、元のレポートには含まれておらず、修正の検証中に発見されました。再帰を解消するものの、`push.apply`を維持する修正は、依然としてDoS攻撃を可能にします。
### `max`と`maxLength`が有効にならない理由
両方のクラッシュは、展開処理の前に、**解析**処理中に発生します。ペイロードはグループごとに1つの結果を生成するため、出力サイズは入力に対して線形に増加し、決して制限要因にはなりません。`expand(payload, { max: 1, maxLength: 1 })`でもオーバーフローが発生します。
### 影響
`expand()`関数に、直接、または`minimatch`や`glob`を通じて、ユーザーが提供したグローブパターンとして、信頼できない文字列を渡すアプリケーションは、クラッシュする可能性があります。Node.jsでは、アプリケーションが捕捉しない`RangeError`が発生し、プロセスが終了するため、ユーザー入力をグローブ処理するサーバーは、認証されていないリモートからのサービス拒否攻撃を受ける可能性があります。
`minimatch`自体の`MAX_PATTERN_LENGTH`の制限(65,536)は、ベクトル1に対する対策にはなりません。オーバーフローの閾値は、この制限値よりもかなり低い位置にあります。minimatch 10.2.6で確認されており、64,003バイトのパターンが長さのチェックを通過し、`minimatch.braceExpand()`と`new minimatch.Minimatch()`の両方でオーバーフローが発生します。
これは、可用性に関する問題であり、コードの実行やデータの漏洩はありません。
### 回帰ではない
5.0.8と5.0.9は、同じ繰り返し回数でオーバーフローが発生するため、この問題は最近の注意喚起よりも前に存在していました。これらの修正は、この問題に到達していませんでした。1.1.18、2.1.4、3.0.6、5.0.8、および5.0.9で、すべて同じ閾値で影響を受けることが確認されました。
### 修正
`parseCommaParts()`関数は、部分的な要素をチャンク間で引き継ぐループとして書き換えられ、配列への追加は、`push.apply`ではなく、要素ごとのループを使用するように変更されました。冗長な`if (!str) return ['']`のガードは削除されました。このループは、空文字列の場合に`['']`を独自に返します。
古い実装と新しい実装の同等性は、差分テストによって検証されました。検証対象は、`{`, `}`, `,`, `a`という文字で構成される最大7文字までの文字列と、30万件のランダムな入力の合計322,000件であり、不一致はゼロでした。
### 重要度に関する注意
CVSS 3.1による評価では、このパッケージの他の可用性に関する注意喚起(GHSA-mh99-v99m-4gvg、GHSA-rgw5-rvv9-x895)との整合性を考慮し、7.5の「高」と評価されました。報告者は、CVSS 4.0では6.9の「中」と自己評価しています(`CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N`)。
### 謝辞
baeseungwon1010氏が、動作する概念実証と修正案を提示して報告しました。ベクトル2は、メンテナによる検証中に特定されました。
影響を受けるパッケージ:
- npm (JavaScript) brace-expansion: 影響を受けるバージョンは4.0.0以上、5.0.10未満。5.0.10で修正済み。
- npm (JavaScript) brace-expansion: 影響を受けるバージョンは3.0.0以上、3.0.7未満。3.0.7で修正済み。
- npm (JavaScript) brace-expansion: 影響を受けるバージョンは2.0.0以上、2.1.5未満。2.1.5で修正済み。
- npm (JavaScript) brace-expansion: 影響を受けるバージョンは1.1.19未満。1.1.19で修正済み。