Nodemailer: アドレスパーサーの自由テキストフォールバックにおける二次的なバックトラッキングにより、リモートでのサービス拒否が可能になる

### 概要

`addressparser` が厳密な解析でアドレスを見つけられない場合、`/\s*\b[^@\s]+@[^\s]+\b\s*/` というパターンを使用して、自由テキストからアドレスを抽出します。このパターンは二次的にバックトラッキングを行います。`[^@\s]+` は、すべてのオフセットから再試行され、次に `@` が現れるまで文字列が再スキャンされます。これにより、Node.js のイベントループが数十秒間ブロックされる可能性があります。

GHSA-prgh-xp8r-p3m5 よりも脆弱性を悪用しやすいです。約 43 秒の遅延を引き起こすのに 273KB だけで済みますが、コメントを結合した形状では、約 10 秒の遅延を引き起こすのに約 1.5MB 必要でした。

### 詳細

`src/addressparser/index.ts` 内のフォールバック機能は、このパターンを検索として実行します。`[^@\s]+` は、空白文字や `@` を含みません。そのため、各開始オフセットから、次に現れる `@` または文字列の末尾まで前方にスキャンし、そこで失敗します。エンジンは単に 1 文字ずつ進み、これを繰り返します。次の 3 つの条件が満たされると、すべてのオフセットで失敗します。

- 文字列に `@` が全く含まれていない
- `@` の後に何も含まれていない
- `@` の前に何も含まれていない

4 つ目のケースでは、有効なアドレスが存在しますが、長い文字列の後に配置されているため、一致が見つかる前に長い文字列全体が走査されます。

### 実証コード

```js
const addressparser = require('nodemailer/lib/addressparser');
const s = Date.now();
addressparser(' >' + '>[x][x]'.repeat(40000)); // 273KB
console.log(Date.now() - s, 'ms'); // 約 43000 ms、ブロック状態
```

10.0.5 で測定した結果:

| 値 | 解析時間 |
| --- | --- |
| `'[x]'.repeat(40000)` (117KB) | 9.0 秒 |
| `'[x]'.repeat(40000) + '@'` (117KB) | 8.9 秒 |
| `'@' + '[x]'.repeat(40000)` (117KB) | 8.8 秒 |
| `' >' + '>[x][x]'.repeat(40000)` (273KB) | 42.9 秒 |

### 影響

アルゴリズムの複雑さによるサービス拒否攻撃。ノードはシングルスレッドであるため、このブロックがプロセス全体を停止させてしまいます。認証なしでアクセス可能な場所は、受信ヘッダーの値がこのパーサーに渡される場所のすべてです。特に、メールパーサーがその例です。また、ユーザーが提供した文字列がメッセージのアドレスとして使用されるアプリケーションの入力からもアクセス可能です。これは、`mime-node`がメッセージの作成時に`to`、`from`、および`cc`を解析するためです。

### 修正

検索処理は、パターンが一致する可能性のあるオフセットを1つだけ見つける、よりシンプルな線形処理に置き換えられました。その後、そのオフセットに固定の正規表現が適用されます。マッチの結果は変更されていません。以前の実装との比較で、340万件のランダムな文字列に対して、マッチするオフセットとマッチしたテキストの両方を検証しました。さらに、80万件の完全な解析比較も行いました。

この問題は、GHSA-prgh-xp8r-p3m5のレポートの検証中に発見されましたが、外部には報告されていません。

影響を受けるパッケージ:
- npm (JavaScript) nodemailer: 影響範囲は10.0.5以下、10.0.6で修正済み。