
PostgreSQL の全文検索(tsvector/tsquery)に見つかった範囲外書き込み脆弱性 CVE-2026-14662 を、修正前(18.4)と修正後(18.6)を Docker で並べて動かして検証した記録と発表資料
PostgreSQL の全文検索データ型(tsvector / tsquery)に見つかった
CVE-2026-14662 について、
修正前(18.4)と修正後(18.6)を Docker で同時に動かし、挙動の差を実際に観測した記録です。
セキュリティ学習用にまとめたもので、発表資料も同梱しています。
| 項目 | 内容 |
|---|
| CVE | CVE-2026-14662 |
| 対象 | PostgreSQL の tsvector / tsquery |
| 種類 | 整数のラップアラウンドによる確保サイズ不足と範囲外書き込み |
| CVSS | 8.8 / 10.0(High) |
| 公開日 | 2026-08-13 |
| 修正版 | 18.5、17.11、16.15、15.19、14.24 |
弱点の連鎖としては次の形になります。
CWE-190(整数オーバーフロー)→ CWE-131(バッファサイズの誤った計算)→ CWE-787(範囲外書き込み)
=根本原因 =最終的な影響
.
├── docs/
│ └── presentation.md 発表資料(脆弱性の解説 + CWEの解説)
└── docker/
├── README.md 再現環境の使い方
├── docker-compose.yml
├── init/ 両バージョンに流す共通の初期化SQL
├── test/ PoC と デモ用SQL
└── run.sh 起動→PoC実行→結果表示
Docker と Docker Compose があれば、以下だけで再現できます。
cd docker
./run.sh
18.4 と 18.6 のコンテナが立ち上がり、同一の初期化SQLを投入したうえで、 同じ PoC を両方に流して結果を並べて表示します。 詳細は docker/README.md を参照してください。
| テスト | PostgreSQL 18.4(修正前) | PostgreSQL 18.6(修正後) |
|---|---|---|
| tsquery の自己OR結合を繰り返す | 18回までエラーなく成功(最終 8,650,748 バイト) | 17回目で ERROR: tsquery is too large |
| 合計長 1,200,000 バイトの単語配列 | 成功してしまう | ERROR: string is too long for tsvector (1200000 bytes, max 1048575 bytes) |
| 3,000 バイトの単語1個 | 成功してしまう | ERROR: word is too long (3000 bytes, max 2046 bytes) |
修正前は、内部表現の上限(20ビットのビットフィールドに由来する MAXSTRPOS = 1,048,575)を
超えるデータをエラーひとつ出さずに受理してしまいます。
なお 18.6 が「17回目ちょうど」で停止する理由は計算で説明でき、 理論値と実測値がバイト単位で一致することを確認しています(詳細は発表資料)。
差分の確認には PostgreSQL 公式リポジトリのクローンを使いましたが、 容量が大きい(各 185MB)ため本リポジトリには含めていません。 必要な場合は次のように取得してください。
git clone --branch REL_18_4 --depth 1 https://github.com/postgres/postgres.git postgres-18.4
git clone --branch REL_18_6 --depth 1 https://github.com/postgres/postgres.git postgres-18.6
修正が入ったファイルは以下の3つです。
src/backend/utils/adt/tsquery_util.csrc/backend/utils/adt/tsvector.csrc/backend/utils/adt/tsvector_op.c