CVE-2026-0593

WP Go Maps (formerly WP Google Maps) <= 10.0.04 - Missing Authorization to Authenticated (Subscriber+) Map Engine Setting Modification

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
10.0.05
Patched in
1d
Time to patch

Description

The WP Go Maps (formerly WP Google Maps) plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the processBackgroundAction() function in all versions up to, and including, 10.0.04. This makes it possible for authenticated attackers, with Subscriber-level access and above, to modify global map engine settings.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=10.0.04
PublishedJanuary 24, 2026
Last updatedJanuary 24, 2026
Affected pluginwp-google-maps

What Changed in the Fix

Changes introduced in v10.0.05

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan outlines the steps required to exploit a missing authorization vulnerability in WP Go Maps (formerly WP Google Maps) versions up to 10.0.04, allowing a Subscriber-level user to modify global map engine settings. ### 1. Vulnerability Summary The vulnerability exists in the `WPGMZA…

Show full research plan

This research plan outlines the steps required to exploit a missing authorization vulnerability in WP Go Maps (formerly WP Google Maps) versions up to 10.0.04, allowing a Subscriber-level user to modify global map engine settings.

1. Vulnerability Summary

The vulnerability exists in the WPGMZA\AdminNotices class, specifically in the processBackgroundAction() method (hooked to the AJAX action wpgmza_persisten_notice_quick_action). The method fails to perform a capability check (e.g., current_user_can('manage_options')) before executing background tasks associated with persistent admin notices. An authenticated attacker with Subscriber-level access can trigger the swap_internal_engine action, which modifies the global map engine configuration (switching from Legacy to Atlas Novus).

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: wpgmza_persisten_notice_quick_action (Note the typo: persisten instead of persistent)
  • Vulnerable Function: WPGMZA\AdminNotices::processBackgroundAction()
  • Authentication: Authenticated (Subscriber+)
  • Payload Parameter: slug=switch_engines
  • Impact: Modifies the wpgmza_internal_engine setting, potentially breaking map functionality or changing the UI/UX site-wide.

3. Code Flow

  1. Entry Point: The plugin registers the AJAX hook in includes/class.admin-notices.php line 115:
    add_action('wp_ajax_wpgmza_persisten_notice_quick_action', array($this, 'processBackgroundAction'));
  2. Processing: When a Subscriber sends a request with action=wpgmza_persisten_notice_quick_action, WordPress invokes processBackgroundAction().
  3. Trigger: The function (based on the AdminNotices::create call on line 64) looks up the persistent notice with the slug switch_engines.
  4. Sink: The notice switch_engines is defined with an ajax_action of swap_internal_engine. The processBackgroundAction method executes this action, which updates the global map engine settings via the InternalEngine class or direct option updates.

4. Nonce Acquisition Strategy

The plugin localizes a global JavaScript object containing the necessary AJAX nonce for authenticated users.

  1. Shortcode/Page: The AdminNotices are initialized on the WordPress admin dashboard. Any logged-in user (including Subscribers) can access wp-admin/index.php.
  2. Procedure:
    • Navigate to /wp-admin/ as a Subscriber.
    • Use browser_eval to extract the nonce from the wpgmza_global_vars object.
  3. JS Variable: window.wpgmza_global_vars?.nonce
  4. Fallback: If not found there, check window.WPGMZA?.ajax_nonce.

5. Exploitation Strategy

The goal is to force the plugin to switch the global internal engine setting.

Request Details:

  • URL: http://[target]/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=wpgmza_persisten_notice_quick_action&slug=switch_engines&security=[NONCE]
    
    (Note: The parameter name for the nonce in this plugin is typically security.)

6. Test Data Setup

  1. Plugin State: Ensure WP Go Maps is installed and active.
  2. Initial Config: Set the internal engine to legacy to ensure the "switch" notice is targetable:
    wp option update wpgmza_internal_engine legacy
  3. Attacker: Create a subscriber user:
    wp user create attacker attacker@example.com --role=subscriber --user_pass=password

7. Expected Results

  • The AJAX request should return a successful response (likely a JSON object or 1).
  • The global WordPress option wpgmza_internal_engine (or the internal setting managed by the plugin) will be changed from legacy to atlas-novus.

8. Verification Steps

  1. Check Setting: Use WP-CLI to verify the change:
    wp option get wpgmza_internal_engine
    • Success: Output is atlas-novus.
    • Failure: Output remains legacy.
  2. Check Notice: Verify if the notice was dismissed in the database:
    wp db query "SELECT dismissed FROM wp_wpgmza_admin_notices WHERE name='switch_engines'"

9. Alternative Approaches

If the slug parameter is not the direct trigger, processBackgroundAction might accept an id or ajax_action parameter directly.

  • Alternative Body 1: action=wpgmza_persisten_notice_quick_action&ajax_action=swap_internal_engine&security=[NONCE]
  • Alternative Body 2 (Notice ID): First, find the ID of the switch_engines notice:
    wp db query "SELECT id FROM wp_wpgmza_admin_notices WHERE name='switch_engines'"
    Then use: action=wpgmza_persisten_notice_quick_action&id=[ID]&security=[NONCE]

Note on Typo: If the request fails with a 400 error, verify the hook name in the actual installed source code, as wpgmza_persisten_notice_quick_action (missing 't') is the literal hook used in the vulnerable version.

Research Findings
Static analysis — not yet PoC-verified

Summary

The WP Go Maps plugin for WordPress is vulnerable to unauthorized modification of data due to missing capability checks in the `AdminNotices` class. Authenticated attackers with Subscriber-level access and above can trigger the `processBackgroundAction` AJAX function to modify the global map engine configuration, potentially switching the site from the Legacy engine to Atlas Novus without administrator permission.

Vulnerable Code

// includes/class.admin-notices.php line 330
	public function dismissFromPostAjax(){
		if (empty($_POST['slug']) || empty($_POST['wpgmza_security']) || !wp_verify_nonce($_POST['wpgmza_security'], 'wpgmza_ajaxnonce')) {
			wp_send_json_error(__( 'Security check failed, import will continue, however, we cannot provide you with live updates', 'wp-google-maps' ));
		}

---

// includes/class.admin-notices.php line 349
	public function processBackgroundAction(){
		if (empty($_POST['relay']) || empty($_POST['wpgmza_security']) || !wp_verify_nonce($_POST['wpgmza_security'], 'wpgmza_ajaxnonce')) {
			wp_send_json_error(__( 'Security check failed, import will continue, however, we cannot provide you with live updates', 'wp-google-maps' ));
		}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/wp-google-maps/10.0.04/includes/class.admin-notices.php /home/deploy/wp-safety.org/data/plugin-versions/wp-google-maps/10.0.05/includes/class.admin-notices.php
--- /home/deploy/wp-safety.org/data/plugin-versions/wp-google-maps/10.0.04/includes/class.admin-notices.php	2026-01-14 08:32:20.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/wp-google-maps/10.0.05/includes/class.admin-notices.php	2026-03-17 12:24:24.000000000 +0000
@@ -328,7 +328,9 @@
 	 * @return void
 	*/
 	public function dismissFromPostAjax(){
-		if (empty($_POST['slug']) || empty($_POST['wpgmza_security']) || !wp_verify_nonce($_POST['wpgmza_security'], 'wpgmza_ajaxnonce')) {
+		global $wpgmza;
+		
+		if (empty($_POST['slug']) || empty($_POST['wpgmza_security']) || !wp_verify_nonce($_POST['wpgmza_security'], 'wpgmza_ajaxnonce') || !$wpgmza->isUserAllowedToEdit()) {
 			wp_send_json_error(__( 'Security check failed, import will continue, however, we cannot provide you with live updates', 'wp-google-maps' ));
 		}
 
@@ -347,7 +349,9 @@
 	 * @return void
 	 */
 	public function processBackgroundAction(){
-		if (empty($_POST['relay']) || empty($_POST['wpgmza_security']) || !wp_verify_nonce($_POST['wpgmza_security'], 'wpgmza_ajaxnonce')) {
+		global $wpgmza;
+
+		if (empty($_POST['relay']) || empty($_POST['wpgmza_security']) || !wp_verify_nonce($_POST['wpgmza_security'], 'wpgmza_ajaxnonce') || !$wpgmza->isUserAllowedToEdit()) {
 			wp_send_json_error(__( 'Security check failed, import will continue, however, we cannot provide you with live updates', 'wp-google-maps' ));
 		}

Exploit Outline

To exploit this vulnerability, an attacker with a Subscriber-level account must first obtain a valid AJAX nonce. This nonce is typically localized in the `wpgmza_global_vars` JavaScript object on the WordPress admin dashboard for any logged-in user. The attacker then sends a POST request to `/wp-admin/admin-ajax.php` with the action `wpgmza_persisten_notice_quick_action` (noting the literal typo in the hook). By setting the `relay` parameter to `switch_engines` and providing the valid nonce in `wpgmza_security`, the plugin will execute the `swap_internal_engine` action. This modifies the `wpgmza_internal_engine` global option, switching the map engine without the required 'manage_options' capability.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.