针对 PostgreSQL 全文搜索数据类型(tsvector / tsquery)中发现的
CVE-2026-14662,
本文记录了在 Docker 中同时运行修复前(18.4)与修复后(18.6)版本,并实际观察行为差异的过程。
本内容为安全学习用途整理,并附带演示资料。
| 项目 | 内容 |
|---|
| 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 字节的单词 | 竟然成功 | 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