Лаборатория валидации Docker и PoC на Python для CVE-2026-89274, доказывающие выполнение произвольных шорткодов в WP Recipe Maker <= 10.8.1 через rating-comment reviewBody.
Материалы для security-исследования по воспроизведению и валидации CVE-2026-89274: WP Recipe Maker <= 10.8.1 выполняет произвольные зарегистрированные шорткоды WordPress внутри метаданных JSON-LD рецепта, внедрённых через одобренный комментарий с рейтингом.
do_shortcode_safe)AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N) - CWE-94Используйте только на системах, которыми вы владеете или на которые у вас есть явное разрешение на тестирование. PoC публикует один комментарий с рейтингом, содержащий лабораторный маркерный шорткод. Деструктивные шорткоды не используются, и ничего не записывается на диск.
Статус: доказано в предоставленной лаборатории.
WP Recipe Maker 10.8.1 (WordPress 7.1.2, модель карточки рецепта по умолчанию):
comment posted : "[cve89274]" + wprm-comment-rating=5 on the recipe's parent post
result : JSON-LD on the rendered page contains
"reviewBody":"CVE89274-SHORTCODE-FIRED"
(marker shortcode executed server-side at render time)
10.8.2 : shortcode stripped, marker absent (patched negative control)
Это демонстрирует серверное выполнение произвольного зарегистрированного шорткода с выводом, встроенным в метаданные страницы и раскрываемым каждому посетителю. Это не демонстрирует RCE; влияние зависит от того, какие шорткоды зарегистрированы на цели (раскрытие постов/метаданных, шорткоды плагинов с побочными эффектами).
WPRM_Metadata::sanitize_metadata() рекурсивно санитизирует каждое скалярное
поле массива структурированных метаданных рецепта:
// includes/public/class-wprm-metadata.php:553, WP Recipe Maker 10.8.1
$sanitized = strip_shortcodes( wp_strip_all_tags( do_shortcode( $metadata ) ) );
// 10.8.2
$sanitized = strip_shortcodes( wp_strip_all_tags( WPRM_Instacart::do_shortcode_safe( $metadata ) ) );
do_shortcode() выполняет шорткод первым; обёртка strip_shortcodes()
лишь удаляет теги из уже выполненного вывода. Одно из полей, reviewBody,
заполняется дословно из comment_content одобренных комментариев, несущих
метазначение wprm-comment-rating (class-wprm-metadata.php:1016), выбираемых
по родительскому посту рецепта (post_id => $recipe->parent_post_id(), строка 973) -
посту или странице, где встроена карточка рецепта.
Замена в 10.8.2, WPRM_Instacart::do_shortcode_safe()
(class-wprm-instacart.php:501), сохраняет только внутреннее содержимое и
ничего не выполняет.
[wprm-recipe])./wp-comments-post.php с шорткодом в теле
и wprm-comment-rating=5.review JSON-LD, и
sanitize_metadata() выполняет шорткод. Его вывод заменяет текст
комментария внутри reviewBody, видимый каждому посетителю.Требования: Docker с Compose v2, Python 3.10+ на хосте.
./lab verify
Собирает лабораторию 10.8.1, требует срабатывания маркера, затем собирает
лабораторию 10.8.2 и требует его отсутствия. Удалить всё можно с помощью
./lab reset.
Уязвимый контроль:
[!!!] SHORTCODE EXECUTION CONFIRMED
evidence: 'CVE89274-SHORTCODE-FIRED' present in the rendered recipe page
context : ..."reviewBody":"CVE89274-SHORTCODE-FIRED","author":...
RESULT: VULNERABLE CONTROL CONFIRMED
Пропатченный контроль:
[=] shortcode text present but NOT executed: output was stripped
RESULT: PATCHED CONTROL CONFIRMED
Маркер на странице только внутри отображаемого комментария (необработанный текст) не принимается как доказательство; маркер должен появиться как выполненный вывод в метаданных.
./lab start vulnerable # 10.8.1 lab on http://127.0.0.1:9482
./lab test # assert marker fires
./lab start patched # 10.8.2 lab
./lab test # assert absence
./lab status
./lab reset
Запуск PoC вручную (по умолчанию loopback; для авторизованных внешних целей требуется явное переопределение):
python3 poc/poc_cve_2026_89274.py --url http://127.0.0.1:9482 --post-id 5
python3 poc/poc_cve_2026_89274.py --url https://target.example \
--allow-authorized-non-loopback [--insecure]
Шаблон nuclei (nuclei/cve-2026-89274.yaml) — это только проверка версии
(stable tag в readme.txt <= 10.8.1). Поведенческая цепочка требует отправки
комментария плюс перехода одобрения, что непрактично выразить в nuclei;
Python PoC выполняет полный сценарий.
| Версия | Оценка |
|---|---|
| WP Recipe Maker 10.8.1 | Выполнение шорткода воспроизведено от начала до конца |
| WP Recipe Maker 10.8.2 | Пропатченный негативный контроль воспроизведён |
| WP Recipe Maker <= 10.8.0 | Затронуто согласно advisory; по отдельности не тестировалось |
.
├── .github/workflows/validate.yml
├── .gitignore
├── LICENSE
├── README.md
├── SECURITY.md
├── docker-compose.yml
├── lab
├── nuclei/
│ └── cve-2026-89274.yaml
└── poc/
└── poc_cve_2026_89274.py
Не коммитится: assets/ (zip-архивы плагинов), .lab-state, __pycache__/.
| Утверждение | Статус |
|---|---|
| Выполнение шорткода через reviewBody комментария с рейтингом | Доказано (10.8.1) |
| Вывод выполнения раскрывается в отрендеренном JSON-LD | Доказано |
| Пропатченный негативный контроль (10.8.2) | Доказано |
| Конфигурация по умолчанию (приватный CPT рецепта + родительский пост) | Доказано (это топология лаборатории) |
| Конфигурация с публичным типом записи рецепта | Не тестировалось |
| Собственный REST-эндпоинт рейтинга WPRM как альтернативная точка входа | Не тестировалось |
| Влияние за пределами вывода зарегистрированного шорткода (RCE) | Не заявлено |
Запускайте этот репозиторий только на системах, которыми вы владеете или на которые
у вас есть явное разрешение на тестирование. Драйвер лаборатории отклоняет варианты,
отличные от vulnerable/patched, PoC отклоняет не-loopback цели, если не указан
--allow-authorized-non-loopback, а порт Compose привязан к 127.0.0.1.
См. SECURITY.md по обработке раскрытия. Этот репозиторий не содержит производственных целей, данных клиентов, токенов доступа или доказательств из реальных систем.
MIT - см. LICENSE.