Vulnerability in Google WordPress Plugin Grants Attacker Search Console Access
15/May/2020
Note: This entry was posted in Research, Vulnerabilities, WordPress Security on May 13, 2020 by Chloe Chamberland
15/May/2020
Note: This entry was posted in Research, Vulnerabilities, WordPress Security on May 13, 2020 by Chloe Chamberland
[SHOWTOGROUPS=4,20]
On April 21st, our Threat Intelligence team discovered a vulnerability in Site Kit by Google, a WordPress plugin installed on over 300,000 sites. This flaw allows any authenticated user, regardless of capability, to become a Google Search Console owner for any site running the Site Kit by Google plugin.
We filed a security issue report with Google on April 21, 2020. A patch was released a few weeks later on May 7, 2020.
This is considered a critical security issue that could lead to attackers obtaining owner access to your site in Google Search Console. Owner access allows an attacker to modify sitemaps, remove pages from Google search engine result pages (SERPs), or to facilitate black hat SEO campaigns. We strongly recommend an immediate update to the latest version of this plugin. At the time of writing, that is version 1.8.0 of Site Kit by Google.
Wordfence Premium customers received a new firewall rule on April 21, 2020 to protect against exploits targeting this vulnerability. Free Wordfence users will receive this rule after thirty days, on May 21, 2020.
Description: Google Search Console Privilege Escalation
Affected Plugin: Site Kit by Google
Plugin Slug: google-site-kit
Affected Versions: <= 1.7.1
CVE ID: Will be updated once identifier is supplied.
CVSS Score: 9.1 (Critical)
CVSS Vector: CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:L
Fully Patched Version: 1.8.0
Site Kit by Google is a plugin used to obtain and display insights on a site’s visitors and search performance as well as advertising performance, page speed insights and other metrics from Google services in the WordPress dashboard. It does this by initially connecting to a Google Search Console account, later providing additional capabilities to connect to Analytics, AdSense, PageSpeed Insights, Optimize, and Tag Manager.
Site Kit by Google Dashboard.
In order to establish the first connection with Site Kit and Google Search Console, the plugin generates a proxySetupURL that is used to redirect a site’s administrator to Google OAuth and run the site owner verification process through a proxy.
proxySetupURL Disclosure
Due to the lack of capability checks on the admin_enqueue_scripts action, the proxySetupURL was displayed as part of the HTML source code of admin pages to any authenticated user accessing the /wp-admin dashboard.
More specifically, the admin_enqueue_scripts action triggers the enqueue_minimal_admin_script function which enqueues the googlesitekit-base assest and ultimately includes the ‘googlesitekit-base-data‘ that returns the inline base data. This includes the proxySetupURL.
Here is a look at the inline_js_base_data function that retrieves the data to display in the WordPress dashboard’s source code as part of the the admin_enqueue_scripts action. This includes the proxySetupURL.
A closer look at the data discoverable in the source code of the admin dashboard:
proxySetupURL found in the source code.
This was fixed in the latest version of the plugin by the addition of a capability check on the admin_enqueue_scripts action. This prohibits the inline_js_base_data from being included in administrative pages for users who do not have the appropriate privileges, such as subscribers. This prevents the proxySetupURL from being displayed to unauthorized users.
Unprotected Verification
In addition to displaying the proxySetupURL to any authenticated user, we discovered that the verification request used to verify a site’s ownership was a registered admin action that, again, did not have any capability checks. This allowed verification requests to come from any authenticated WordPress user, including those with minimal permissions.
The admin_action_googlesitekit_proxy_setup action was registered here.
This is the function that handles the verification request:
Here’s a look at the verification request sent during the process:
[code
/wp-admin/index.php?action=googlesitekit_proxy_setup&googlesitekit_code=[SITEKIT-CODE]&googlesitekit_verification_token=[VERIFICATION TOKEN]&googlesitekit_verification_token_type=FILE&nonce=[NONCE]
[/code]
This was fixed in the latest version with a capability check added on the handle_verification_token function to verify that a verification request occurred during a legitimate authenticated session with a user that had administrative permissions to SETUP the Site Kit by Google plugin.
These two flaws made it possible for subscriber-level users to become Google Search Console owners on any affected site.
The Impact
When a new owner for a property in Google Search Console is set up, a message is sent via email saying, “Property owners can change critical settings that affect how Google Search interacts with your site or app.”
There are several ways an attacker could make use of Google Search Console owner access for a site. For malicious attackers, the ability to manipulate search engine result pages through Blackhat SEO is particularly attractive. Additionally, an attacker could use search console access in conjunction with another exploit that involves malicious content being injected on a site for monetization.
An owner in Google Search Console can do things like request that URLs be removed from the Google Search engine, view competitive performance data, modify sitemaps, and more.
Unwarranted Google Search Console owner access on a site has the potential to hurt the visibility of a site in Google search results and impact revenue as an attacker removes URLs from search results. More specifically, it could be used to aid a competitor who wants to hurt the ranking and reputation of a site to better improve their own reputation and ranking.
Verifying the Integrity of Google Search Console Ownership
Fortunately, there are ways to verify and monitor if any new Google Search Console owners have been added and the Wordfence firewall provides your site with protection.
As our site cleaning team often sees malicious property owners in Google Search Console added to hacked sites, we’ve included some guidance from them.
Monitoring
Google will alert you via email whenever a new Search Console owner has been added. If you receive one of these emails and have not recently added a new Google Search Console owner, take immediate action and remove the unknown owner.
[/SHOWTOGROUPS]
On April 21st, our Threat Intelligence team discovered a vulnerability in Site Kit by Google, a WordPress plugin installed on over 300,000 sites. This flaw allows any authenticated user, regardless of capability, to become a Google Search Console owner for any site running the Site Kit by Google plugin.
We filed a security issue report with Google on April 21, 2020. A patch was released a few weeks later on May 7, 2020.
This is considered a critical security issue that could lead to attackers obtaining owner access to your site in Google Search Console. Owner access allows an attacker to modify sitemaps, remove pages from Google search engine result pages (SERPs), or to facilitate black hat SEO campaigns. We strongly recommend an immediate update to the latest version of this plugin. At the time of writing, that is version 1.8.0 of Site Kit by Google.
Wordfence Premium customers received a new firewall rule on April 21, 2020 to protect against exploits targeting this vulnerability. Free Wordfence users will receive this rule after thirty days, on May 21, 2020.
Description: Google Search Console Privilege Escalation
Affected Plugin: Site Kit by Google
Plugin Slug: google-site-kit
Affected Versions: <= 1.7.1
CVE ID: Will be updated once identifier is supplied.
CVSS Score: 9.1 (Critical)
CVSS Vector: CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:L
Fully Patched Version: 1.8.0
Site Kit by Google is a plugin used to obtain and display insights on a site’s visitors and search performance as well as advertising performance, page speed insights and other metrics from Google services in the WordPress dashboard. It does this by initially connecting to a Google Search Console account, later providing additional capabilities to connect to Analytics, AdSense, PageSpeed Insights, Optimize, and Tag Manager.

Site Kit by Google Dashboard.
In order to establish the first connection with Site Kit and Google Search Console, the plugin generates a proxySetupURL that is used to redirect a site’s administrator to Google OAuth and run the site owner verification process through a proxy.
proxySetupURL Disclosure
Due to the lack of capability checks on the admin_enqueue_scripts action, the proxySetupURL was displayed as part of the HTML source code of admin pages to any authenticated user accessing the /wp-admin dashboard.
More specifically, the admin_enqueue_scripts action triggers the enqueue_minimal_admin_script function which enqueues the googlesitekit-base assest and ultimately includes the ‘googlesitekit-base-data‘ that returns the inline base data. This includes the proxySetupURL.
366 367 368 369 370 371 372 373 374 | new Script_Data( 'googlesitekit-base-data', array( 'global' => '_googlesitekitBaseData', 'data_callback' => function () { return $this->get_inline_base_data(); }, ) ), |
Here is a look at the inline_js_base_data function that retrieves the data to display in the WordPress dashboard’s source code as part of the the admin_enqueue_scripts action. This includes the proxySetupURL.
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 | /** * Modifies the base data to pass to JS. * * @since 1.2.0 * * @param array $data Inline JS data. * @Return array Filtered $data. */ private function inline_js_base_data( $data ) { $first_admin_id = (int) $this->first_admin->get(); $current_user_id = get_current_user_id(); // If no first admin is stored yet and the current user is one, consider them the first. if ( ! $first_admin_id && current_user_can( Permissions::MANAGE_OPTIONS ) ) { $first_admin_id = $current_user_id; } $data['isFirstAdmin'] = ( $current_user_id === $first_admin_id ); $data['splashURL'] = esc_url_raw( $this->context->admin_url( 'splash' ) ); $auth_client = $this->get_oauth_client(); if ( $auth_client->using_proxy() ) { $access_code = (string) $this->user_options->get( Clients\OAuth_Client::OPTION_PROXY_ACCESS_CODE ); $data['proxySetupURL'] = esc_url_raw( $auth_client->get_proxy_setup_url( $access_code ) ); $data['proxyPermissionsURL'] = esc_url_raw( $auth_client->get_proxy_permissions_url() ); } return $data; } |
A closer look at the data discoverable in the source code of the admin dashboard:

proxySetupURL found in the source code.
This was fixed in the latest version of the plugin by the addition of a capability check on the admin_enqueue_scripts action. This prohibits the inline_js_base_data from being included in administrative pages for users who do not have the appropriate privileges, such as subscribers. This prevents the proxySetupURL from being displayed to unauthorized users.
97 98 99 100 101 102 103 104 105 106 107 108 | add_action( 'admin_enqueue_scripts', $register_callback ); add_action( 'wp_enqueue_scripts', $register_callback ); add_action( 'admin_enqueue_scripts', function() { if ( ! current_user_can( Permissions::AUTHENTICATE ) ) { return; } $this->enqueue_minimal_admin_script(); } ); |
Unprotected Verification
In addition to displaying the proxySetupURL to any authenticated user, we discovered that the verification request used to verify a site’s ownership was a registered admin action that, again, did not have any capability checks. This allowed verification requests to come from any authenticated WordPress user, including those with minimal permissions.
The admin_action_googlesitekit_proxy_setup action was registered here.
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | add_action( 'admin_action_' . Google_Proxy::ACTION_SETUP, function () { $this->verify_proxy_setup_nonce(); }, -1 ); add_action( 'admin_action_' . Google_Proxy::ACTION_SETUP, function () { $code = $this->context->input()->filter( INPUT_GET, 'googlesitekit_code', FILTER_SANITIZE_STRING ); $site_code = $this->context->input()->filter( INPUT_GET, 'googlesitekit_site_code', FILTER_SANITIZE_STRING ); $this->handle_site_code( $code, $site_code ); $this->redirect_to_proxy( $code ); } ); |
This is the function that handles the verification request:
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 | /** * Handles receiving a verification token for a user by the authentication proxy. * * @since 1.1.0 * @since 1.1.2 Runs on `admin_action_googlesitekit_proxy_setup` and no longer redirects directly. */ private function handle_verification_token() { $verification_token = $this->context->input()->filter( INPUT_GET, 'googlesitekit_verification_token', FILTER_SANITIZE_STRING ); $verification_type = $this->context->input()->filter( INPUT_GET, 'googlesitekit_verification_token_type', FILTER_SANITIZE_STRING ); $verification_type = $verification_type ?: self::VERIFICATION_TYPE_META; if ( empty( $verification_token ) ) { return; } switch ( $verification_type ) { case self::VERIFICATION_TYPE_FILE: $this->authentication->verification_file()->set( $verification_token ); break; case self::VERIFICATION_TYPE_META: $this->authentication->verification_meta()->set( $verification_token ); } add_filter( 'googlesitekit_proxy_setup_url_params', function ( $params ) use ( $verification_type ) { return array_merge( $params, array( 'verify' => 'true', 'verification_method' => $verification_type, ) ); } ); } |
Here’s a look at the verification request sent during the process:
[code
/wp-admin/index.php?action=googlesitekit_proxy_setup&googlesitekit_code=[SITEKIT-CODE]&googlesitekit_verification_token=[VERIFICATION TOKEN]&googlesitekit_verification_token_type=FILE&nonce=[NONCE]
[/code]
This was fixed in the latest version with a capability check added on the handle_verification_token function to verify that a verification request occurred during a legitimate authenticated session with a user that had administrative permissions to SETUP the Site Kit by Google plugin.
400 401 402 | if ( ! current_user_can( Permissions::SETUP ) ) { wp_die( esc_html__( 'Sorry, you are not allowed to do that.', 'google-site-kit' ), 403 ); } |
These two flaws made it possible for subscriber-level users to become Google Search Console owners on any affected site.
The Impact
When a new owner for a property in Google Search Console is set up, a message is sent via email saying, “Property owners can change critical settings that affect how Google Search interacts with your site or app.”
There are several ways an attacker could make use of Google Search Console owner access for a site. For malicious attackers, the ability to manipulate search engine result pages through Blackhat SEO is particularly attractive. Additionally, an attacker could use search console access in conjunction with another exploit that involves malicious content being injected on a site for monetization.
An owner in Google Search Console can do things like request that URLs be removed from the Google Search engine, view competitive performance data, modify sitemaps, and more.
Unwarranted Google Search Console owner access on a site has the potential to hurt the visibility of a site in Google search results and impact revenue as an attacker removes URLs from search results. More specifically, it could be used to aid a competitor who wants to hurt the ranking and reputation of a site to better improve their own reputation and ranking.
Verifying the Integrity of Google Search Console Ownership
Fortunately, there are ways to verify and monitor if any new Google Search Console owners have been added and the Wordfence firewall provides your site with protection.
As our site cleaning team often sees malicious property owners in Google Search Console added to hacked sites, we’ve included some guidance from them.
Monitoring
Google will alert you via email whenever a new Search Console owner has been added. If you receive one of these emails and have not recently added a new Google Search Console owner, take immediate action and remove the unknown owner.
[/SHOWTOGROUPS]