我们的 AI 引擎 Neutron 在加州大学伯克利分校的 CyberGym 基准测试中取得了 97.1% 的成绩。 了解更多

深度解析

深度解析

Drupal Commerce 访问控制绕过,已在野外被利用(CVE-2026-118539)

2.41 与 3.3.13 之前的 Drupal Commerce 允许受限用户通过 JSON:API 接手其他卖家的变体和优惠券;已在野外被利用。

摘要

  • Drupal Commerce Core 不保护跨所有权边界连接产品、变体、优惠券和促销的实体字段。持有受限权限的用户可通过 JSON:API 或 REST 接手其他卖家的产品变体,或关联其他促销的优惠券。顾客还能修改自己购物车的受限字段,如状态和总额。
  • Drupal 在自有量表中将该缺陷评为 Highly critical(21/25),并声明它正在野外被积极利用。公告没有给出攻击者、规模或指标。截至 2026-10-30,CVE-2026-118539 没有 CVSS 分数。
  • 2.41 之前的每个 Commerce Core 版本以及 3.0.0 到 3.3.12 的每个版本都受影响。2.x 分支在此修复之前自 2024 年 8 月起没有发布过版本。
  • 升级到 Commerce Core 3.3.13,旧线上则升到 2.41,并按公告要求审计现有订单是否存在不一致。公开材料支持的审计角度见"如何检查是否已被入侵"。

我受影响吗?

以下条件全部成立时,您处于暴露状态:

  • 安装的 Commerce Core 模块版本低于 2.41,或处于 3.0.0 到 3.3.12 之间(含)。
  • 除全权店铺管理员外,还有账户能写入 commerce 实体:更新自己购物车的顾客,或持有 commerce 权限的账户,如更新自己的产品、管理变体或更新自己的促销。该缺陷是这类账户的访问绕过。
  • 存在 JSON:API 或 REST API 访问。修复的测试对每条接管路径都使用它。JSON:API 随 Drupal 核心提供。

顾客不需要任何 commerce 权限:修复前,对自己购物车有更新权限的顾客可以通过 JSON:API 或 REST 修改订单及订单项的受限字段,如 state、total_price、adjustments、unit_price 和 title,并能访问该订单的管理路由。卖家之间的接管路径需要一个持有受限 commerce 权限的账户。无法查看某些变体(如未发布产品的变体)的账户,也能从 JSON:API 集合过滤中得知这些变体存在。

分支 受影响版本 修复版本
Commerce Core 3.x 3.0.0 到 3.3.12 3.3.13(2026-10-28)
Commerce Core 2.x 及更早 2.41 之前的所有版本 8.x-2.41(2026-10-28)

两个修复在同一天发布。2.x 分支的上一版本 8.x-2.40 发布于 2024-08-22,使用它的站点已经两年多没有更新。

检查站点运行的版本:

# Composer-installed sites: the resolved version in the lock file
grep -A1 '"name": "drupal/commerce"' composer.lock | grep version

# Or ask Composer directly
composer show drupal/commerce 2>/dev/null | grep ^versions

# Without Composer: the module's .info.yml carries the version when
# packaged from drupal.org
grep -r "version:" web/modules/contrib/commerce/*.info.yml 2>/dev/null

如何修复?

  1. 使用 Composer 的标准 Drupal 流程:composer require 'drupal/commerce:^3.3.13' --with-all-dependencies,2.x 线上用 composer require 'drupal/commerce:^2.41' --with-all-dependencies。
  2. 代码变更后执行站点惯用的更新流程,然后清理缓存:drush cr。
  3. 重新应用针对该模块的任何自定义补丁,因为两个分支都发生了变动。
  4. 按公告要求,用下面的检查审计现有订单。

不存在配置层面的绕过方案。公告没有给出任何方案,而修复自带的测试表明,绕过路径只有在新字段级检查到位后才关闭。

根本原因是什么?

Commerce 实体在实体层面有访问控制,在字段层面却没有,因此把一个卖家的实体连到另一个卖家的引用字段,任何被允许操作自己实体的账户都能编辑。

Commerce Core 通过产品、变体、促销和优惠券销售商品与服务,每个都有各自的权限。持有"update own commerce_product"的账户可以编辑自己的产品。3.3.13 的 diff 显示,没有任何机制阻止这类账户同时编辑跨越所有权的引用字段:产品的变体列表、优惠券所属的促销、促销引用的优惠券,以及改变全站行为的店铺标志。

修复为每个实体类型引入 restricted_fields 属性,并在新的访问控制处理器中检查它。下面是 3.3.13 diff 中变体的处理器:

// modules/product/src/ProductVariationAccessControlHandler.php
$restricted_fields = $this->entityType->get('restricted_fields') ?? [];
if ($operation == 'edit' && in_array($field_definition->getName(), $restricted_fields, TRUE)) {
  $result = AccessResult::allowedIfHasPermission($account, $this->entityType->getAdminPermission());
  /** @var \Drupal\commerce_product\Entity\ProductVariationInterface|null $variation */
  $variation = $items?->getEntity();
  if ($result->isAllowed() || !$variation?->isNew()) {
    return $result;
  }
  // Users who can create variations can set these fields on new variations
  // (e.g. through JSON:API or REST), as on the variation add form, which
  // allows adding variations to any product.
  return $result->orIf(AccessResult::allowedIfHasPermission($account, "manage {$variation->bundle()} commerce_product_variation"));
}

return parent::checkFieldAccess($operation, $field_definition, $account, $items);

受限字段现在包括:

  • 变体:product_id。
  • 优惠券:promotion_id。
  • 促销:coupons。
  • 店铺:is_default。
  • 订单和订单项:承载所有权、金额和状态的字段,如 uid、store_id、state、order_items、total_price、adjustments、unit_price、title 和 purchased_entity,另有订单的 coupons、cart、checkout_flow、checkout_step、payment_gateway 和 payment_method。
  • 支付方式:网关、所有者、远程 ID 和卡片字段。

编辑它们需要管理权限、在处理器允许时的全局更新或按订单类型的更新权限,或者对新变体而言,新增表单本身使用的变体管理权限。

同一个 diff 关闭了这些引用打开的删除路径。Promotion::postDelete() 现在只删除其促销与被删实体匹配的优惠券,并带有注释"Coupons belonging to other promotions might be referenced (e.g. through JSON:API), those must not be deleted"。产品侧的对应实现只删除产品自己的变体。

多条路由也缺少权限检查:由于顾客对自己的购物车有更新权限,/admin/ 下所有只检查订单访问的订单管理路由(包括 entity.commerce_order.manage_coupons_form、订单表单模式路由和订单项路由)现在都要求"access commerce administration pages"。优惠券还完全没有查询访问控制处理器,因此实体自动补全路由向任何能到达它的账户列出所有优惠券代码;新的选择插件把该列表限制为持有"administer commerce_promotion"或"update any commerce_promotion"的账户。

如何被利用?

没有公开的利用代码。修复自带的功能测试记录了修复前成功、修复后失败的确切请求:

  1. 有权创建自己产品的用户发送一个 JSON:API POST,创建引用另一个产品变体的产品。修复前,变体的所有权转移到新产品;修复后,请求以 422 失败并返回"belongs to another product"。
  2. 促销所有者发送 JSON:API PATCH,通过改变 promotion_id 关系把自己的一个优惠券移到另一个促销。修复前优惠券会移动;修复后请求返回 403。
  3. 任何能到达实体自动补全路由的账户都会在结果中收到优惠券代码,包括它无权管理的促销的代码。
  4. JSON:API 集合查询会匹配该账户无法查看的变体,包括未发布产品的变体,并将其列为已省略(omitted),从而暴露过滤条件命中了它们。

缺陷被积极利用是 Drupal 的声明。没有公开文章点名攻击者、发送的请求或受影响的站点,公告也没有给出任何指标。

攻击如何流动?

一句话:受限权限账户通过 JSON:API 或 REST 编辑一个引用字段,把另一个卖家的变体或另一个促销的优惠券关联到自己控制的实体,平台随之转移所有权。

flowchart LR A["持有受限 commerce
权限的账户"] --> B["JSON:API 或 REST
写请求"] B --> C["引用字段编辑:
变体、优惠券、
promotion_id"] C --> D["没有字段级检查:
请求被接受"] D --> E["另一个卖家的变体
或他人的优惠券被关联
到攻击者的实体"] E --> F["对卖家的
经济影响"] G["自动补全路由:
向所有调用者
列出优惠券代码"] --> D

攻击者能做什么?

持有受限 commerce 权限的账户可以把另一个卖家的产品变体移到自己控制的实体,在促销之间移动优惠券,并列出从未打算给它看的优惠券代码。修复前,删除一个精心构造的促销还会删除属于其他促销的优惠券。Drupal 将影响总结为可能"给卖方带来经济影响"的访问绕过。

条件是:篡改购物车订单字段,只需一个有购物车的顾客;卖家之间的接管,需要持有某种 commerce 权限的账户;两者都需要 API 访问。按查询修复的描述,无查看权限的账户也能得知隐藏变体的存在。

公告的利用声明是唯一公开的滥用证据。除了"正在野外被利用"之外它什么也没说,因此把任何运行受影响版本且存在多卖家或多角色账户的站点视为自未知日期起就已暴露,并按要求审计。

为什么修复有效?

修复增加了缺失的一层:恰好针对跨越所有权边界的字段的字段级访问控制,由在写入引用之前运行的访问控制处理器强制执行。每种实体的模式相同:实体类型声明其受限字段,checkFieldAccess() 在账户既无管理权限、也无(视实体类型而定的)全局更新或按订单类型的更新权限时拒绝编辑。

三个伴随变更关闭剩余路径:

  • CouponSelection::getReferenceableEntities() 对无法管理促销的账户返回空列表,自动补全路由不再泄漏代码。兑换优惠券仍然有效,因为验证与列举是不同的路径。
  • Promotion::postDelete() 和产品的对应实现在删除被引用实体之前检查所有权。
  • 订单管理路由(包括 manage_coupons_form)获得其权限要求。

该修复对其测试覆盖的路径是完整的:变体接管、优惠券移动、优惠券列举、顾客对购物车、订单项和支付方式受限字段的编辑、删除副作用和管理路由。

添加自有引用字段的贡献模块需要自行加以保护。restricted_fields 机制可扩展:模块通过 hook_entity_type_build() 注册字段,修复本身也对订单的优惠券字段使用了这个钩子。请检查您站点运行的模块。

如何检查是否已被入侵?

公告只给出一条指示:审计订单是否存在不一致。没有公布任何指标、请求形态或攻击者细节,因此审计从数据模型入手:

  • 列出 product_id 变更为由另一账户(而非创建该变体的账户)拥有的产品的变体。所有权翻转是接管的特征。
  • 列出 promotion_id 与最初发放它的促销不同的优惠券,以及优惠券列表中出现了从未分配过的优惠券的促销。
  • 检查先于或绕过其所属促销的优惠券兑换,以及所应用优惠券属于无关促销的订单。
  • 审查来自受限权限账户对 commerce 实体的 JSON:API 和 REST 写入的访问日志,以及返回了优惠券结果的实体自动补全请求。
  • 确认没有促销删除曾移除仍属于其他促销的优惠券。

访问日志比代码侧更重要:失败的尝试一旦到达字段就会在 API 日志中留下 403 或 422,而受影响版本上的成功接管会留下 2xx(200,JSON:API 创建则为 201)。

时间线

  • 2024-08-22:Commerce Core 8.x-2.40 发布,是 2.x 分支在此修复前的最后一个版本。
  • 2026-10-28:Commerce Core 3.3.13 和 8.x-2.41 带着访问控制修复被打上标签。
  • 2026-10-28:Drupal 发布 SA-CONTRIB-2026-254,评为 Highly critical 21/25,声明该缺陷正在野外被积极利用。
  • 2026-10-29:CISA 的 KEV 目录中仍然没有该缺陷的条目,已在数据源中核对。
  • 2026-10-30:Drupal CNA 发布 CVE-2026-118539 记录,没有 CVSS 分数,描述为允许强行浏览的缺失授权。The Hacker News 当日报道了该公告。

2.x 分支两年的空窗,然后是同一天发布的修复与公告:CVE-2026-118539 的公开时间线。
图 1:CVE-2026-118539 的公开时间线,从上一个 2.x 版本到修复、公告和 CVE 记录。来源:Commerce 的 Git 标签、Drupal 公告与 CVE 记录,2026 年 10 月 30 日核对

常见问题

有 CVSS 分数吗?

没有。2026-10-30 发布的 CVE 记录不带任何度量,公告使用 Drupal 自有的风险量表:Highly critical,21/25。其向量采用 Drupal 自有记法,而非 CVSS:AC:None/A:None/CI:Some/II:Some/E:Exploit/TD:All。E:Exploit 分量反映了野外利用声明。

匿名访客能接管产品吗?

不能。接管产品或变体需要一个持有受限 commerce 权限的账户。但修复也阻止了不需要任何 commerce 权限的顾客通过 JSON:API 或 REST 修改自己购物车的受限字段(如状态和总额),隐藏的变体也不再以已省略条目出现在 JSON:API 集合中。公告将该缺陷定位给卖方,其审计指示针对订单数据。

我的站点只有管理员。我暴露吗?

卖家之间的接管路径不会波及您,这些路径需要一个持有某种 commerce 权限但没有管理权限的账户。但顾客仍是风险:任何有购物车的顾客都能通过 JSON:API 或 REST 修改该购物车的受限字段,如状态、总额和订单项价格。请立即修复,并按公告要求审计订单。

修复会改变店铺的运作吗?

可能在一个地方:在没有管理权限的情况下在订单上管理优惠券的用户,现在需要输入优惠券代码而不是从自动补全中选择,因为那个列表会泄漏代码。优惠券兑换本身不变。

2.x 分支错过了什么?

2024 年 8 月以来的一切,而此修复在那里应用了同样的访问控制层。2.41 标签为旧代码路径带上了字段限制,升级仍是同样的一步迁移。

修复期间我应该禁用 JSON:API 吗?

这会缩小接管面,只读模式能完全阻止写入,但它不能替代更新:自动补全路由和删除副作用并不需要 JSON:API。先修复,然后重新启用您的消费者所需的 API 面。

用 Ostorlab 盘点您的 Drupal 站点

Ostorlab 的攻击面发现会测绘您暴露在互联网上的站点及其平台,找出每个公开的 Drupal 资产,抢在攻击者之前检查其模块版本。

参考文献

  • Drupal 安全公告 SA-CONTRIB-2026-254,Commerce Core,Highly critical,2026-10-28 发布: https://www.drupal.org/sa-contrib-2026-254 (2026 年 10 月 30 日核对)
  • CVE-2026-118539 记录,Drupal CNA,2026-10-30 发布,允许强行浏览的缺失授权: https://cveawg.mitre.org/api/cve/CVE-2026-118539 (2026 年 10 月 30 日核对)
  • Commerce Core 3.3.12 到 3.3.13 的比较,访问控制修复、处理器与测试: https://git.drupalcode.org/project/commerce/-/compare/3.3.12...3.3.13 (2026 年 10 月 30 日核对)
  • Commerce Core 8.x-2.41 标签,创建于 2026-10-28: https://git.drupalcode.org/project/commerce/-/tags/8.x-2.41 (2026 年 10 月 30 日核对)
  • Commerce Core 8.x-2.40 标签,创建于 2024-08-22,上一个 2.x 版本: https://git.drupalcode.org/project/commerce/-/tags/8.x-2.40 (2026 年 10 月 30 日核对)
  • The Hacker News,"Hackers Actively Exploit Highly Critical Drupal Commerce Core Authorization Bypass Flaw",2026 年 10 月 30 日: https://thehackernews.com/2026/10/hackers-actively-exploit-highly.html (2026 年 10 月 30 日核对)
  • CISA KEV 目录 JSON 数据源,2026 年 10 月 30 日核对 CVE-2026-118539(未列入): https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json (2026 年 10 月 30 日核对)