WordPress 核心更新窗口 RCE,已在 7.1.4 修复 (CVE-2026-119977)
WordPress 4.7 至 7.1.3 将核心更新解包到可预测的 Web 可访问路径,未认证攻击者竞速利用该窗口执行代码;已在 7.1.4 修复。
摘要
- WordPress 核心更新程序中的一个缺陷让未认证攻击者能在 WordPress 解包核心更新的几秒钟窗口内在服务器上执行代码。受影响版本为 4.7.0 至 7.1.3。Picus Security 的 Umut Bayram 负责任地披露了该缺陷。
- Wordfence 的 CVE 记录将该缺陷评为 8.1 High,CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H,而 WordPress 自己的公告将同一场竞态评为 Low。截至 10 月 30 日,Wordfence 在 24 小时内拦截了 62,969 次针对它的攻击。
- 修复随 2026 年 10 月 28 日发布的 WordPress 7.1.4 交付,并向后移植到直至 4.7 的每个分支。没有报告任何入侵,且截至 2026 年 10 月 31 日,该 CVE 不在 CISA 的 KEV(已知被利用漏洞)目录中。
- 立即更新到 7.1.4 或您所在分支的向后移植版本,然后在 Web 服务器日志中排查
wp-content/upgrade下的 PHP 文件请求。尚未安装补丁的站点在每次更新时都打开一个脆弱窗口,包括更新到 7.1.4 本身。
我受影响吗?
未认证攻击需要同时满足以下条件:
- 您运行的 WordPress 版本为 4.7.0 至 7.1.3,位于下表任一分支。
- 您的站点通过 WordPress 更新程序应用核心更新,它会把完整更新包解包到 Web 服务器上的
wp-content/upgrade/。 - 该目录可通过 Web 访问(Wordfence 指出许多服务器正是如此),且其中的文件作为 PHP 运行。
- 攻击者赢得竞速:必须在解包与清理之间命中暂存文件,Wordfence 在实验室环境中观察到该窗口只持续几秒。
该路径在每个受影响版本上都是可预测的,因此第四个条件关乎时机而非知识。攻击者不需要站点上的任何账户,也不需要任何人的交互。
| 分支 | 受影响版本 | 修复版本 |
|---|---|---|
| WordPress 7.1.x | 7.1.0 至 7.1.3 | 7.1.4 |
| WordPress 7.0.x | 7.0.0 至 7.0.7 | 7.0.8 |
| WordPress 6.9.x | 6.9.0 至 6.9.10 | 6.9.11 |
| WordPress 6.8.x | 6.8.0 至 6.8.11 | 6.8.12 |
| WordPress 6.7.x | 6.7.0 至 6.7.10 | 6.7.11 |
| WordPress 6.6.x | 6.6.0 至 6.6.10 | 6.6.11 |
| WordPress 6.5.x | 6.5.0 至 6.5.13 | 6.5.14 |
| WordPress 6.4.x | 6.4.0 至 6.4.13 | 6.4.14 |
| WordPress 6.3.x | 6.3.0 至 6.3.13 | 6.3.14 |
| WordPress 6.2.x | 6.2.0 至 6.2.14 | 6.2.15 |
| WordPress 6.1.x | 6.1.0 至 6.1.15 | 6.1.16 |
| WordPress 6.0.x | 6.0.0 至 6.0.17 | 6.0.18 |
| WordPress 5.9.x | 5.9.0 至 5.9.19 | 5.9.20 |
| WordPress 5.8.x | 5.8.0 至 5.8.18 | 5.8.19 |
| WordPress 5.7.x | 5.7.0 至 5.7.20 | 5.7.21 |
| WordPress 5.6.x | 5.6.0 至 5.6.22 | 5.6.23 |
| WordPress 5.5.x | 5.5.0 至 5.5.23 | 5.5.24 |
| WordPress 5.4.x | 5.4.0 至 5.4.24 | 5.4.25 |
| WordPress 5.3.x | 5.3.0 至 5.3.26 | 5.3.27 |
| WordPress 5.2.x | 5.2.0 至 5.2.29 | 5.2.30 |
| WordPress 5.1.x | 5.1.0 至 5.1.27 | 5.1.28 |
| WordPress 5.0.x | 5.0.0 至 5.0.30 | 5.0.31 |
| WordPress 4.9.x | 4.9.0 至 4.9.34 | 4.9.35 |
| WordPress 4.8.x | 4.8.0 至 4.8.33 | 4.8.34 |
| WordPress 4.7.x | 4.7.0 至 4.7.38 | 4.7.39 |
WordPress 占所有网站的 39.5%。W3Techs 10 月 31 日的调查显示了主要版本的使用分布,但未区分已修复与存在漏洞的具体版本。请根据上表判断您的站点是否受影响。
请检查您运行的每个站点的版本。命令行方式:
wp core version
没有命令行时,在仪表盘的“仪表盘、更新”下或“概览”框中读取版本。要检查解包目录的 HTTP 响应,请从您控制的机器上对您自己的站点发起请求:
curl -s -o /dev/null -w "%{http_code}\n" https://your-site.example/wp-content/upgrade/
仅凭目录响应无法判断暂存的 PHP 文件是否可访问。200 可能只是索引页面;目录返回 403 或 404 也不能证明其中的具体文件已被阻止访问。请检查服务器配置并安装已修复版本。
如何修复?
将每个站点更新到其分支的修复版本,或更新到 7.1.4:
- 备份站点及其数据库。
- 从仪表盘更新:仪表盘、更新、立即更新。WordPress 7.1.4 是安全发布,因此支持后台自动更新的站点会按发布公告所述自动收到它。
- 或从命令行更新:
wp core update
如果需要保留在 7.0 分支,请用以下命令替代上面的命令:
wp core update --version=7.0.8
请指定上表中您所在分支的修复版本,不要连续执行这两条命令。
- 更新后,删除更新程序自身没有清理掉的
wp-content/upgrade/下的残留文件。
对于尚无法更新的站点,一个变通方案可以关闭 Web 可达性这一条件:
- 在 Web 服务器层拒绝访问解包目录。nginx 在 server 块中:
location ^~ /wp-content/upgrade/ { return 403; }
- Apache 在站点配置或
.htaccess中:
RedirectMatch 403 ^/wp-content/upgrade/
该变通方案只覆盖此 CVE。它从 Web 层阻断暂存文件,因此安装器和其他任何暂存的 PHP 文件都不会运行。它对其他缺陷毫无作用,并且必须保留到站点升级到修复版本为止。
修复后的 WordPress 写入更新文件夹的 index.php 只阻止目录列表。对随机工作目录名的直接请求仍然有效,这就是服务器层拦截更强的原因。
根本原因是什么?
更新程序把每次核心更新解包到一个工作目录,其名称仅由包的文件名推导而来,并且位于 Web 服务器对外提供服务的文件夹中。 在 WordPress 7.1.3 中,WP_Upgrader::unpack_package() 在 wp-admin/includes/class-wp-upgrader.php 第 378 行从包构建路径,其中没有任何不可预测的内容:
$upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/';
// ...
// We need a working directory - strip off any .tmp or .zip suffixes.
$working_dir = $upgrade_folder . basename( basename( $package, '.tmp' ), '.zip' );
因此,名为 wordpress-7.1.4.zip 的核心更新包被解包到 wp-content/upgrade/wordpress-7.1.4,这是攻击者可以在更新开始之前算出的路径。该包包含完整的 WordPress 目录树,包括 wp-admin/setup-config.php 安装向导。
向导是缺陷的另一半。setup-config.php 只在它旁边已存在 wp-config.php 文件时才拒绝运行,见 wp-admin/setup-config.php 第 58 至 60 行:
// Check if wp-config.php has been created.
if ( file_exists( ABSPATH . 'wp-config.php' ) ) {
wp_die(
发布包附带的是 wp-config-sample.php 而非 wp-config.php,因此暂存的目录树永远不会触发该检查。更新窗口内对暂存向导的未认证请求会运行它,并根据提交的表单值把一个 wp-config.php 写入暂存目录树:数据库名、用户、密码、主机和表前缀。WordPress 7.1.4 改变了这条链的三个环节,下一节将展示。
如何被利用?
攻击者轮询可预测的暂存路径以命中暂存安装器,直到站点解包更新,赢得持续数秒的竞速,再把暂存安装器变成代码执行。没有公开的概念验证代码,Wordfence 也只发布了它拦截的请求模式;以下步骤来自受影响的源码、修复补丁和 Wordfence 的描述:
- 攻击者算出目标即将安装的版本的暂存路径,例如
/wp-content/upgrade/wordpress-7.1.4/,并轮询其中的wp-admin/setup-config.php。Wordfence 看到两个来源对小型站点群轮询了约 14.5 小时,其他来源则测试了许多暂存目录和版本名的变体。 - 当站点的更新程序解包时,轮询开始命中暂存的向导。实验室环境中该窗口只持续数秒,因此攻击是重复轮询,而不是单次构造请求。
- 暂存的向导运行,因为暂存目录树中不存在
wp-config.php。攻击者用指向自己控制的数据库的设置填写表单,向导把这些设置写入暂存目录树内的wp-config.php。 - 攻击者随后如 Wordfence 所述,让暂存的 WordPress 副本对接自己的数据库。通过包含插件和主题上传的暂存管理界面,他们进一步获得 PHP 执行。
- 另外,在 7.1.4 之前,更新的复制步骤会把工作目录中的文件安装到站点根目录,只跳过
wp-content和wp-includes/version.php。攻击者写入工作目录的wp-config.php因此会被复制到站点根目录。它在那里随每个请求执行,并把真实站点指向攻击者的数据库。 - WordPress 在更新后删除工作目录,窗口关闭。在第 5 步存活下来的配置替换会持久存在;只留在暂存目录树中的内容则不会。
Wordfence 给出的成立条件与这些步骤一致:
- 包含安装器文件的完整包更新
- 对暂存目录树的公开 Web 和 PHP 访问
- 可预测或被发现的暂存路径
- 在 WordPress 清理临时文件之前完成攻击的足够时间
攻击如何流动?
未认证攻击者在站点更新期间轮询可预测的暂存路径,到达暂存安装器,并在清理前把它变成代码执行。流程中缺失的检查是工作目录从未拥有过的不可预测性。
wp-content/upgrade/wordpress-7.1.4"] B --> C["攻击者轮询暂存的
setup-config.php"] C --> D["暂存树中没有
wp-config.php:检查通过"] D --> E["向导写入攻击者控制的
wp-config.php"] E --> F["暂存副本对接
攻击者的数据库"] F --> G["通过暂存管理界面上传插件:
PHP 执行"] E --> H["缺失的检查:复制步骤把暂存的
wp-config.php 安装到根目录"] H --> I["真实站点加载
攻击者的配置"]
攻击者能做什么?
竞速获胜者在更新窗口期间以 WordPress 进程用户身份在 Web 服务器上执行 PHP 代码。在 7.1.4 之前的版本上,他们还可以让配置替换在窗口结束后持久存在。该攻击不需要账户、权限或站点上任何人的交互。
WordPress 安全团队将该问题评为 Low,Wordfence 评为 8.1 High;差异在于竞态,向量将其记录为攻击复杂度 High。
对实际利用的了解范围更窄。截至 2026 年 10 月 30 日,Wordfence 在 24 小时内拦截了 62,969 次针对该缺陷的请求,这些是尝试而非入侵。Wordfence、媒体报道和 WordPress 均未报告任何成功入侵,且截至 2026 年 10 月 31 日,该 CVE 不在 KEV 目录中。
速度是这件事的核心:大规模攻击尝试在修复发布两天后到达,而当时站点仍在向 7.1.4 迁移。
为什么修复有效?
WordPress 7.1.4 在提交 b625b2d49c6a“Upgrade/Install: Improve the handling of the upgrade working directory”中从三点切断了这条链:
$upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/';
- // Clean up contents of upgrade directory beforehand.
+ // Clean up contents of upgrade directory beforehand, keeping its index.php.
$upgrade_files = $wp_filesystem->dirlist( $upgrade_folder );
if ( ! empty( $upgrade_files ) ) {
foreach ( $upgrade_files as $file ) {
+ if ( 'index.php' === $file['name'] ) {
+ continue;
+ }
+
$wp_filesystem->delete( $upgrade_folder . $file['name'], true );
}
}
- // We need a working directory - strip off any .tmp or .zip suffixes.
- $working_dir = $upgrade_folder . basename( basename( $package, '.tmp' ), '.zip' );
+ /*
+ * The upgrade directory is web-served. Keep it from being listed, as core does
+ * for wp-content and its plugins and themes directories, so the name of the
+ * working directory created below cannot be discovered from a directory index.
+ */
+ if ( ! $wp_filesystem->exists( $upgrade_folder . 'index.php' ) ) {
+ $wp_filesystem->put_contents( $upgrade_folder . 'index.php', "<?php\n// Silence is golden.\n", FS_CHMOD_FILE );
+ }
+
+ // We need a working directory.
+ $working_dir = $upgrade_folder . $this->get_working_dir_name( $package );
新的私有方法附加了一个随机后缀:
private function get_working_dir_name( $package ) {
// Strip off any .tmp or .zip suffixes.
$name = basename( basename( $package, '.tmp' ), '.zip' );
return $name . '-' . wp_generate_password( 16, false );
}
第三处改动在 update-core.php 中,复制步骤的跳过清单增加了攻击者写入的那个文件:
- $skip = array( 'wp-content', 'wp-includes/version.php' );
+ $skip = array( 'wp-content', 'wp-includes/version.php', 'wp-config.php' );
随机后缀使工作目录路径不再可预测,攻击者无法预先计算它。index.php 文件消除了目录列表这一发现随机名称的途径。跳过清单条目意味着,即使攻击者找到该目录,也无法再让自己的 wp-config.php 被安装到站点根目录。
该修复对更新程序中的这条链是完整的,每个分支向后移植版本都携带同样的三处改动。它没有移除更新文件夹本身的 Web 访问。这就是“如何修复?”中的服务器层拦截仍是值得的纵深防御的原因。
如何检查是否已被入侵?
在您的 Web 服务器访问日志中搜索此攻击的请求模式。nginx 的默认日志对每个请求记录一行,其中包含路径:
# Nginx: requests to PHP files under the staging path, case-insensitive; decode encoded paths separately.
grep -iE "wp-content/upgrade/[^ ]+\.php" /var/log/nginx/access.log
在 Apache 上,替换为您自己的访问日志路径。请求中出现暂存路径,尤其是 setup-config.php,正是此缺陷的样子:
# Apache: any request to the staged installer, on any version name.
grep -iE "wp-content/upgrade/.*/setup-config\.php" /var/log/apache2/access.log
判断前请解码百分号编码的路径,因为 Wordfence 报告攻击者会变换目录和版本名的拼写。合法客户端没有理由请求这些路径,因此任何命中都值得调查来源地址及其后续;单次命中是线索而非证据。然后检查竞速成功会留下什么:
# Any PHP file left in the staging tree.
find wp-content/upgrade -name "*.php" | sort
一个包含 // Silence is golden. 的 index.php 是修复后的 WordPress 自己写入的文件。其他任何 PHP 文件,尤其是 wp-config.php,都是需要调查的线索。Wordfence 还建议检查陌生的管理员账户、您没有安装过的插件和您不认识的 PHP 文件。失败的攻击可能除了轮询本身之外不留痕迹。
时间线
- 2026-10-28:WordPress 发布包含修复提交 b625b2d49c6a 的 7.1.4,并将修复向后移植到从 7.0.8 到 4.7.39 的每个分支。
- 2026-10-29:WordPress 发布公告 GHSA-4w3m-c66w-69mg,将竞态条件评为 Low,并感谢 Picus Security 的 Umut Bayram。
- 2026-10-30:The Hacker News 报道了 Wordfence 的统计:24 小时内拦截 62,969 次攻击;没有报告入侵。
- 2026-10-31:CVE-2026-119977 记录由 Wordfence 发布,CVSS v3.1 评分为 8.1 High。该缺陷截至此日期不在 CISA 的 KEV 目录中。
常见问题
更新到 7.1.4 的过程中我会在那几秒内暴露吗?
会,暴露时间就是更新持续的几秒。执行更新的代码是更新前安装的版本,因此更新到 7.1.4 时仍然解包到可预测路径。那一刻的攻击需要已经在轮询您站点的攻击者,而这正是 Wordfence 观察到的。请立即更新而不是等待,并在变更窗口期间保留“如何修复?”中的服务器层拦截。
我的站点运行旧分支。我必须跳到 7.1.4 吗?
不必。WordPress 将修复向后移植到直至 4.7 的每个分支,因此 7.0.8、6.9.11 以及“我受影响吗?”分支表中的每个其他向后移植版本都携带同样的三处改动。跨分支跳跃本身带有兼容性风险,因此您所在分支的向后移植版本是更小的改动。
为什么 WordPress 和 Wordfence 在严重程度上不一致?
WordPress 将底层竞态条件评为 Low,而 Wordfence 的 CVE 记录将其评为 8.1 High、攻击复杂度 High。两者描述的是同一条通往代码执行的未认证路径;Low 评分权衡的是几秒的窗口,High 评分权衡的是赢得它的后果。无论哪种情况,修复都是一样的,攻击遥测也是真实的。
Wordfence 实际观察到什么?
截至 2026 年 10 月 30 日,Wordfence 在 24 小时内拦截了 62,969 次针对此缺陷的请求。两个最大的来源对小型站点群轮询了约 14.5 小时,其他来源测试了许多暂存目录和版本名的变体。这些是防火墙产品拦截的尝试,不是确认的入侵,也没有报告任何受害者。
自动更新足够吗?
自动更新是修复的交付机制,发布公告也确认在支持后台更新的环境中安全发布会自动应用。它们留下的暴露是更新窗口本身。请在更新后将它们与本文章的日志检查结合,并在解包目录可从 Web 访问时加上服务器层拦截。
在攻击者轮询之前找到您的 WordPress 部署
Ostorlab 的 Web Agentic Deep Scan 会清点您的 Web 应用及其框架版本。它能显示您哪些站点运行 WordPress 4.7.0 至 7.1.3,以便您在下一个更新窗口打开之前将它们引导到修复版本。
参考文献
- WordPress 安全公告 GHSA-4w3m-c66w-69mg,“A race condition during core updates that could lead to remote code execution”,2026 年 10 月 29 日发布,附各分支修复版本矩阵:https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-4w3m-c66w-69mg(2026 年 10 月 31 日查询)
- CVE-2026-119977 记录,由 Wordfence CNA 发布,CVSS v3.1 8.1:https://www.cve.org/CVERecord?id=CVE-2026-119977(2026 年 10 月 31 日查询)
- WordPress 7.1.4 发布公告,2026 年 10 月 28 日,感谢 Umut Bayram 报告更新流程问题:https://wordpress.org/news/2026/10/wordpress-7-1-4/(2026 年 10 月 31 日查询)
- 修复提交 b625b2d49c6a,“Upgrade/Install: Improve the handling of the upgrade working directory”,位于 WordPress 7.1.4:https://github.com/WordPress/WordPress/commit/b625b2d49c6a(2026 年 10 月 31 日查询)
- WordPress 7.1.3 源码,
WP_Upgrader::unpack_package()中易受攻击的工作目录推导,以及setup-config.php的已有配置检查:https://raw.githubusercontent.com/WordPress/WordPress/7.1.3/wp-admin/includes/class-wp-upgrader.php 与 https://raw.githubusercontent.com/WordPress/WordPress/7.1.3/wp-admin/setup-config.php(2026 年 10 月 31 日查询) - Wordfence 对 7.1.4 安全发布的分析,“WordPress 7.1.4 Patches Unauthenticated Upgrade-Window RCE; Exploitation Attempts Detected After Release”,2026 年 10 月 29 日:https://www.wordfence.com/blog/2026/10/wordpress-7-1-4-security-release-rce/(2026 年 10 月 31 日查询)
- The Hacker News,“WordPress RCE Flaw Draws Nearly 63,000 Attack Attempts in Just 24 Hours”,2026 年 10 月 30 日,引用 Wordfence 的 Alex Thomas 以及被拦截的 62,969 次攻击:https://thehackernews.com/2026/10/wordpress-rce-flaw-draws-nearly-63000.html(2026 年 10 月 31 日查询)
- Wordfence 针对 WordPress Core 4.7-7.1.3 更新窗口 RCE 的威胁情报条目:https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-core/wordpress-core-470-713-unauthenticated-upgrade-window-staged-installer-remote-code-execution(2026 年 10 月 31 日查询)
- CISA Known Exploited Vulnerabilities 目录 JSON 源,检索 CVE-2026-119977:https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json(2026 年 10 月 31 日查询)
- W3Techs 的 WordPress 使用统计,占所有网站的 39.5% 及版本分布:https://w3techs.com/technologies/details/cm-wordpress(2026 年 10 月 31 日查询)