ARTICLE · 1061652
WordPress插件Authorizer存在权限提升漏洞(POC已公开)CVE-2026-81294

一、漏洞描述
Authorizer 是 WordPress 上做登录控制的插件。登录除密码外还能交给 Google、CAS、LDAP、OAuth2。
漏洞产生出在 OAuth2 这条路上。3.15.1 及更低版本处理外部服务返回的邮箱地址时,跳过了验证状态这一步。邮箱在对方那里确认过没有,不影响后面的比对。
二、漏洞原理
入口是 wp-login.php?external=oauth2,Authorizer 把自己的处理函数挂在 WordPress 的 authenticate 过滤器上。
请求带上这个参数,处理流程直接进到 custom_authenticate_oauth2。
OAuth2 部分按 provider 分成 github、azure、generic 三种走法,出问题的在 github 与 generic 两支。
GitHub 这支先取公开邮箱,取不到就调 /user/emails 把账号上挂的邮箱全拉回来。
接口返回的每一项里,email 之外还有 verified 与 primary。3.15.1 的映射只留 email,verified 被丢在一边,未验证的地址一样进数组。
// src/authorizer/class-authentication.php 3.15.1 github 分支
if ( empty( $email ) ) {
$request = $provider->getAuthenticatedRequest(
'GET',
$provider->getResourceOwnerDetailsUrl( $token ) . '/emails',
$token
);
$attributes['emails'] = array_filter( array_map(
function ( $entry ) {
return empty( $entry['email'] ) ? '' : $entry['email'];
},
(array) $provider->getParsedResponse( $request )
) );
$email = $attributes['emails'];
}
数组往下传到公共部分,逐个用 get_user_by 按邮箱找站内账号。命中就把那个用户对象交回 WordPress,会话随之建立。
// src/authorizer/class-authentication.php 3.15.1 公共匹配
foreach ( $externally_authenticated_emails as $externally_authenticated_email ) {
$user = get_user_by( 'email', Helper::lowercase( $externally_authenticated_email ) );
// Stop trying email addresses once we have found a match.
if ( false !== $user ) {
break;
}
}
generic 这支从资源接口里取 attributes['email']。
另外允许管理员配一个自定义属性名 oauth2_attr_email,取到什么用什么,往下直接进公共匹配,中间没有 email_verified 这一层。
// src/authorizer/class-authentication.php 3.15.1 generic 分支
$email = empty( $attributes['email'] ) ? '' : $attributes['email'];
$username = empty( $attributes['preferred_username'] ) ? '' : $attributes['preferred_username'];
// 自定义邮箱属性名,取到什么用什么
if ( ! empty( $oauth2_attr_email ) && ! empty( $attributes[ $oauth2_attr_email ] ) ) {
if ( is_string( $attributes[ $oauth2_attr_email ] ) ) {
$email = trim( $attributes[ $oauth2_attr_email ] );
} elseif ( is_array( $attributes[ $oauth2_attr_email ] ) ) {
$email = $attributes[ $oauth2_attr_email ];
}
}
// 后面跟一个 authorizer_oauth2_generic_authenticated_email 过滤器,接着进公共匹配
同一份文件里的 OIDC 分支倒是有 email_verified 的判断,由 oidc_require_verified_email 控制,OAuth2 这侧没有对应的开关。
3.15.2 补的就是这两处。
// src/authorizer/class-authentication.php 3.15.2 github 分支
$attributes['emails'] = array_filter( array_map(
function ( $entry ) {
// Filter out empty or unverified email addresses.
if ( empty( $entry['email'] ) || empty( $entry['verified'] ) ) {
return false;
}
return $entry['email'];
},
(array) $provider->getParsedResponse( $request )
) );
// 3.15.2 generic 分支新增
$oauth2_require_verified_email = $auth_settings[ 'oauth2_require_verified_email' . $suffix ] ?? '';
if ( '1' === $oauth2_require_verified_email ) {
if ( empty( $attributes['email_verified'] ) || true !== $attributes['email_verified'] ) {
return new \WP_Error( 'oauth2_email_not_verified', ... );
}
}
GitHub 那支把未验证的项在映射阶段丢掉,无条件生效。
通用 provider 的判断挂在新增的 oauth2_require_verified_email 上,后台多出一个 Require verified email 勾选框,默认不勾。
三、修复建议
升到 3.15.2 或更高,插件目录当前提供 3.16.0。