
Отчет о проверке уязвимости записи за пределами границ CVE-2026-14662 в полнотекстовом поиске PostgreSQL (tsvector/tsquery) путем параллельного запуска в Docker версий до (18.4) и после (18.6) исправления, а также материалы презентации
Это запись о том, как мы запустили одновременно в Docker версии до исправления (18.4) и после исправления (18.6) для уязвимости CVE-2026-14662, обнаруженной в типах данных полнотекстового поиска PostgreSQL (tsvector / tsquery), и фактически наблюдали разницу в поведении.
Материал подготовлен для целей изучения безопасности, также прилагаются слайды презентации.
| Пункт | Содержание |
|---|
| CVE | CVE-2026-14662 |
| Объект | tsvector / tsquery в PostgreSQL |
| Тип | Недостаточный размер выделяемой памяти из-за целочисленного переполнения и запись за пределами буфера |
| 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) |
До исправления данные, превышающие внутренний предел представления (MAXSTRPOS = 1 048 575, происходящий из 20-битного битового поля), принимались без единой ошибки.
Кроме того, причина остановки 18.6 «ровно на 17-м разе» объясняется расчётом, и мы подтвердили, что теоретическое значение и измеренное значение совпадают побайтово (подробности в слайдах презентации).
Для проверки различий мы использовали клон официального репозитория PostgreSQL, но из-за большого объёма (по 185 МБ каждый) они не включены в этот репозиторий. При необходимости получите их следующим образом.
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
Файлы, в которые были внесены исправления, следующие три.
src/backend/utils/adt/tsquery_util.csrc/backend/utils/adt/tsvector.csrc/backend/utils/adt/tsvector_op.c