FlawOpen

flawopen.com/Teardowns/cve-2026-87902-wordpress-page-template-path-traversal

● CVE-2026-87902 · CVSS 9.2[1] · 严重
安全研究 · FlawOpen

CVE-2026-87902:WordPress 页面模板路径遍历

未验证的解码后页面名称进入模板解析,导致未经身份验证的本地 PHP 文件包含;RCE 需要特定主题和 PHP 环境条件。[1]

💡 通俗易懂的原理解析 (ELI5)

想象一位取书前会检查请求的图书管理员。WordPress 检查了一条模板路径,却漏掉了解码后名称对应的路径;特殊标记可能让其离开主题目录。修复会验证名称,并将模板限制在允许目录内。[1], [2], [3]

核心概念与专有名词

页面模板解析
WordPress 按顺序排列 PHP 候选项,并在当前主题中查找首个匹配文件。[1], [2]
路径遍历
若不验证输入,.. 等路径组件可能使文件访问越出预期目录。[1]
本地 PHP 文件包含
加载服务器上已有的 PHP 文件;RCE 还需要其他条件。[1]
`validate_file()`
WordPress 函数,在使用路径前拒绝不允许的路径组件。[3]
CWE-98
CWE-98 — include/require 文件名控制不当:选择 PHP 文件前未充分限制输入。[1], [7]

框架映射

根本原因剖析 (Root Cause)

在 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(最早的回移版本)到 7.1.2(当前分支),每个列出的分支都有单独的修复版本。核对已安装的 Core 版本并应用对应分支的修复。低于 4.7 的版本应升级到受支持版本。
当前主题的目录结构当前父主题或子主题必须包含一个名称以 page- 开头的顶层目录(例如 page-templates)。检查当前启用的父主题和子主题目录。主题变更后重新核实这一条件。
可读取的本地 PHP 文件所选 .php 文件必须存在于当前主题目录之外,并且 Web 服务器账户能够读取。检查 Web 服务器可读取哪些本地 PHP 文件;仅凭 CVE 版本范围不能证明发生了文件包含。
有条件 RCE 的运行环境公告说明只有满足额外 PHP/服务器条件时才可能导致 RCE。示例包括 register_argc_argv=On 时的 pearcmd.php、官方 PHP Docker 镜像,以及运行 PHP 8.5 之前版本的默认 cPanel 配置。评估实际 PHP 运行环境和配置。WordPress 版本受影响本身不能证明 RCE 或系统已被攻陷。

攻击执行流程分解

步骤 1

输入进入模板选择

未认证请求提供用于生成候选项的名称;不需要账户或用户点击。[1]

步骤 2

再次解码

get_page_template() 再次解码名称;受影响版本未验证解码后的候选项。[2], [3]

步骤 3

查找越出根目录

存在 page-* 目录和可读 PHP 文件时,主题可能解析其目录外的文件。[1]

步骤 4

影响有条件

RCE 需要额外 PHP/服务器条件;版本本身不能证明可利用或已入侵。[1]

源代码对比:漏洞与安全实现

此代码片段对比官方 7.1.1 和 7.1.2 标签。补丁在解码后验证值;同一版本还在 locate_template() 限制解析路径。这是上游源码改动,不是完整独立补丁,也不是漏洞利用演示。[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";
    }
}

工程与系统安全加固清单

参考来源