flawopen.com/Teardowns/cve-2026-87902-wordpress-page-template-path-traversal
CVE-2026-87902: обход пути в шаблонах страниц WordPress
Непроверенное декодированное имя страницы попало в выбор шаблона, что позволяло подключать локальный PHP-файл без аутентификации; RCE требовало условий темы и PHP.[1]
Представьте библиотекаря, который проверяет запрос. WordPress проверял один путь к шаблонам, но пропускал путь через декодированное имя; специальные маркеры могли вывести его за пределы темы. Исправление проверяет имя и оставляет шаблон в разрешённом каталоге.[1], [2], [3]
Ключевые понятия и термины
Выбор шаблона страницы- WordPress упорядочивает кандидатов PHP и ищет первый подходящий файл в активной теме.[1], [2]
Обход пути- Компоненты вроде
..могут выйти за пределы каталога, если входные данные не проверены.[1] Подключение локального PHP- Загрузка уже имеющегося на сервере PHP-файла; RCE требует дополнительных условий.[1]
`validate_file()`- Функция WordPress, отклоняющая недопустимые компоненты пути до их использования.[3]
Связи со стандартами
- Ссылка CWE для слабого места, описанного в этом руководстве: CWE-98
- CISA KEV — добавлено 2026-09-25 — CVE-2026-87902
Анализ первопричины
В get_page_template() WordPress декодировал pagename и добавлял page-{name}.php без validate_file(), хотя соседняя ветвь выполняла проверку. Путь мог выйти за пределы темы. Нужны каталог верхнего уровня page-* и читаемый локальный PHP-файл; для RCE нужны дополнительные условия PHP/сервера. Версия 7.1.2 проверяет декодированное значение и ограничивает путь в locate_template(). В бюллетене WordPress эта слабость отнесена к CWE-98 (недостаточный контроль имени файла для PHP include/require); автором обнаружения и ответственного раскрытия указан Robert Ressl.[1], [2], [3], [7]
Границы CVE-2026-87902: уязвимость и условное RCE
| Условие развертывания | Что подтверждают первичные источники | Действие оператора |
|---|---|---|
| Уязвимая ветка WordPress Core | В GHSA уязвимые версии указаны отдельно для каждой ветки: от 4.7.0–4.7.36 до 7.1.0–7.1.1. Соответствующие исправления охватывают версии от 4.7.37 (самый ранний backport) до 7.1.2 (текущая ветка); для каждой указанной ветки предусмотрен отдельный исправленный выпуск. | Сверьте установленную версию Core с исправлением для соответствующей ветки. Обновите версии ниже 4.7 до поддерживаемого выпуска. |
| Структура активной темы | В активной родительской или дочерней теме должен быть каталог верхнего уровня, имя которого начинается с page- (например, page-templates). | Проверьте каталоги обеих активных тем. Повторно проверьте это условие после смены активной темы. |
| Доступный локальный PHP-файл | Выбранный файл .php должен существовать вне каталогов активных тем и быть доступен для чтения учетной записи веб-сервера. | Проверьте, какие локальные PHP-файлы доступны веб-серверу; диапазон версий CVE сам по себе не доказывает включение файла. |
| Среда для условного RCE | В бюллетене RCE описан только при дополнительных условиях PHP/сервера. Среди примеров — pearcmd.php при register_argc_argv=On, официальный PHP-образ Docker и стандартные конфигурации cPanel с PHP ниже 8.5. | Оцените фактическую среду и конфигурацию PHP. Уязвимая версия WordPress сама по себе не доказывает RCE или компрометацию. |
Пошаговый сценарий атаки
Ввод попадает в выбор шаблона
Неаутентифицированный запрос передаёт имя для кандидатов; аккаунт и клик не нужны.[1]
Поиск выходит за корень
При каталоге page-* и читаемом PHP-файле тема может разрешить файл вне своего каталога.[1]
Условное воздействие
RCE требует дополнительных условий PHP/сервера; версия сама по себе не доказывает эксплуатацию или взлом.[1]
Исходный код: Уязвимый vs Защищённый вариант
Этот фрагмент сравнивает официальные теги 7.1.1 и 7.1.2. Исправление проверяет значение после декодирования; тот же выпуск ограничивает разрешённые пути в locate_template(). Это исходный код upstream, не полный самостоятельный патч и не демонстрация эксплуатации.[2], [3]
Фрагмент исходного кода: wp-includes/template.php — get_page_template()
if ( $pagename ) {
$pagename_decoded = urldecode( $pagename );
if ( $pagename_decoded !== $pagename ) {
$templates[] = "page-{$pagename_decoded}.php";
}
}
if ( $pagename ) {
$pagename_decoded = urldecode( $pagename );
if ( $pagename_decoded !== $pagename && 0 === validate_file( $pagename_decoded ) ) {
$templates[] = "page-{$pagename_decoded}.php";
}
}
Чек-лист по защите системы для инженеров
- ✓Установите исправленный выпуск своей ветки и проверьте реально работающий код.[1], [4]
- ✓Учтите доступные из Интернета установки WordPress и неподдерживаемые версии ниже 4.7.[1], [4]
- ✓Если до исправления система была открыта, изучите журналы, неожиданные PHP-файлы и учётные записи; сигнал — повод для расследования, а не самостоятельное доказательство.
- ✓В собственных загрузчиках проверяйте декодированные компоненты и ограничивайте канонический путь разрешёнными каталогами.[1], [3]
- ✓Поддерживайте Core и темы; смена темы может изменить условия воздействия.[1], [4]