CVE-2026-12238

WP Go Maps <= 10.1.01 - Unauthenticated Arbitrary Record Creation

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

Description

The WP Go Maps – Most Popular Map Plugin plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 10.1.01. This is due to the plugin not properly verifying that a user is authorized to perform an action. This makes it possible for unauthenticated attackers to create arbitrary records in plugin database tables (maps, markers, circles, polygons, polylines, rectangles, and point labels) by supplying a WPGMZA-namespaced CRUD-backed class name via the phpClass parameter. The namespace validation check (requiring the 'WPGMZA' prefix) does not prevent exploitation because classes such as WPGMZA\Map and WPGMZA\Marker satisfy it while still triggering an INSERT into the corresponding plugin table before the route rejects the request.

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.1.01
PublishedJune 19, 2026
Last updatedJune 19, 2026
Affected pluginwp-google-maps

What Changed in the Fix

Changes introduced in v10.1.02

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-12238 ## 1. Vulnerability Summary The **WP Go Maps** plugin (up to 10.1.01) is vulnerable to **Unauthenticated Arbitrary Record Creation**. This is due to an authorization bypass in the REST API handling of the `phpClass` parameter. The plugin attempts to val…

Show full research plan

Exploitation Research Plan - CVE-2026-12238

1. Vulnerability Summary

The WP Go Maps plugin (up to 10.1.01) is vulnerable to Unauthenticated Arbitrary Record Creation. This is due to an authorization bypass in the REST API handling of the phpClass parameter. The plugin attempts to validate that the requested class belongs to the WPGMZA namespace but fails to restrict which classes can be instantiated.

When a user provides a CRUD-backed class name (like WPGMZA\Marker or WPGMZA\Map), the plugin's REST API controller instantiates the class. In these specific versions, the instantiation of certain CRUD classes triggers a database INSERT operation using the provided request parameters before the REST route's logic actually validates the user's permissions to perform that action.

2. Attack Vector Analysis

  • Endpoint: /wp-json/wpgmza/v1/datatables (or any route using the phpClass parameter).
  • HTTP Method: POST (or GET via compressed path variables).
  • Vulnerable Parameter: phpClass.
  • Authentication: Unauthenticated.
  • Preconditions: The datatables route is explicitly exempted from nonce checks in includes/class.rest-api.php.

3. Code Flow

  1. Entry Point: The request hits wp-json/wpgmza/v1/datatables.
  2. Route Registration: In includes/class.rest-api.php, the registerRoute method defines the datatables route. It adds a check that sets $doActionNonceCheck = false for the datatables route, allowing unauthenticated access.
  3. Parameter Parsing: RestAPI::getRequestParameters() parses the input.
  4. Vulnerable Logic: The REST callback (likely in includes/class.rest-api.php or a related controller) retrieves the phpClass parameter.
  5. Validation: The code checks if the class starts with WPGMZA\.
  6. Instantiation: The plugin instantiates the class: $instance = new $phpClass($_POST); (or similar).
  7. Sink: The constructor of WPGMZA\CRUD (the parent of Marker, Map, etc.) identifies that no ID was provided and uses the passed data to create a new record in the database.
  8. Rejection: The REST route callback may eventually return a 403 or 401, but the INSERT has already been committed to the database.

4. Nonce Acquisition Strategy

The datatables route is specifically designed to skip nonce checks in this version.
In includes/class.rest-api.php:

$skipNonceRoutes = array('features', 'markers', 'marker-listing', 'datatables');
if(in_array(str_replace('/', '', $route), $skipNonceRoutes)){
    $doActionNonceCheck = false;
}

Conclusion: No nonce is required for this specific exploit.

5. Exploitation Strategy

We will use the http_request tool to send a POST request to the datatables endpoint, supplying WPGMZA\Marker as the phpClass.

Step-by-Step Payload

  • Target URL: [TARGET_URL]/wp-json/wpgmza/v1/datatables
  • Method: POST
  • Content-Type: application/x-www-form-urlencoded
  • Payload Parameters:
    • phpClass: WPGMZA\Marker
    • map_id: 1 (Default map ID)
    • address: Exploit Address
    • title: Exploit Marker
    • lat: 40.7128
    • lng: -74.0060

Expected Response

The server might return a 403 Forbidden or a JSON error message, but the side effect (record creation) will have occurred.

6. Test Data Setup

  1. Verify Plugin: Ensure WP Go Maps <= 10.1.01 is active.
  2. Default Map: Ensure at least one map exists (Map ID 1 is standard).
    wp wpgmza create-map --title="Test Map"
    
  3. Placement: No shortcodes are strictly necessary for the exploit itself since nonces are skipped, but placing [wpgmza id="1"] on a page can help verify the marker appears visually later.

7. Expected Results

  • The HTTP response status may be 403 or 200 (depending on the specific REST controller's error handling).
  • A new record should be present in the wp_wpgmza (or wp_wpgmza_markers) table.

8. Verification Steps

After the exploit, use WP-CLI to check the database for the new marker:

# Check for markers with the 'Exploit Marker' title
wp db query "SELECT * FROM \$(wp db prefix)wpgmza WHERE title='Exploit Marker';"

# Alternatively, if using the v8+ naming convention:
wp db query "SELECT * FROM \$(wp db prefix)wpgmza_markers WHERE title='Exploit Marker';"

9. Alternative Approaches

If the datatables route is hardened in the specific environment, try the markers route or features route, as they also skip nonce checks:

  • Endpoint: /wp-json/wpgmza/v1/markers
  • Endpoint: /wp-json/wpgmza/v1/features

If the application requires the compressed format (as seen in RestAPI::parseCompressedParameters), the payload would need to be JSON-encoded, zlib-compressed, and base64-encoded, then passed as a path variable:
GET /wp-json/wpgmza/v1/datatables/base64[COMPRESSED_DATA]

Research Findings
Static analysis — not yet PoC-verified

Summary

The WP Go Maps plugin is vulnerable to unauthenticated arbitrary record creation due to a missing authorization check on the `datatables` REST API route. Attackers can specify a CRUD-backed class (like WPGMZA\Marker) via the `phpClass` parameter, causing the plugin to instantiate the class and insert a new record into the database before permission checks are applied.

Vulnerable Code

// includes/class.rest-api.php:1118
$skipNonceRoutes = array('features', 'markers', 'marker-listing', 'datatables');
if(in_array(str_replace('/', '', $route), $skipNonceRoutes)){
    $doActionNonceCheck = false;
}

---

// includes/class.rest-api.php:1173 (approximate)
if((class_exists('\\WPGMZA\\MarkerListing') && $reflection->isSubclassOf('\\WPGMZA\\MarkerListing'))
    || (class_exists('\\WPGMZA\\MarkerListing\\AdvancedTable') && ($class == '\\WPGMZA\\MarkerListing\\AdvancedTable' || $reflection->isSubclassOf('\\WPGMZA\\MarkerListing\\AdvancedTable')))){

    $map_id = $request['map_id'];
    $instance = $class::createInstance($map_id);
} else {
    $instance = $class::createInstance();
}

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/wp-google-maps/10.1.01/includes/class.rest-api.php	2026-06-10 08:37:38.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/wp-google-maps/10.1.02/includes/class.rest-api.php	2026-06-15 09:36:06.000000000 +0000
@@ -1170,15 +1170,19 @@
 			return new \WP_Error('wpgmza_invalid_datatable_class', 'Invalid class specified', array('status' => 403));
 		}
 		
-		if((class_exists('\\WPGMZA\\MarkerListing') && $reflection->isSubclassOf('\\WPGMZA\\MarkerListing'))
-			|| (class_exists('\\WPGMZA\\MarkerListing\\AdvancedTable') && ($class == '\\WPGMZA\\MarkerListing\\AdvancedTable' || $reflection->isSubclassOf('\\WPGMZA\\MarkerListing\\AdvancedTable')))){
+		$isMarkerListingSubclass = (class_exists('\\WPGMZA\\MarkerListing') && $reflection->isSubclassOf('\\WPGMZA\\MarkerListing'))
+			|| (class_exists('\\WPGMZA\\MarkerListing\\AdvancedTable') && ($class == '\\WPGMZA\\MarkerListing\\AdvancedTable' || $reflection->isSubclassOf('\\WPGMZA\\MarkerListing\\AdvancedTable')));
 
+		if(!$reflection->isSubclassOf('\\WPGMZA\\DataTable') && !$isMarkerListingSubclass)
+			return new \WP_Error('wpgmza_invalid_datatable_class', 'Specified PHP class must extend WPGMZA\\DataTable', array('status' => 403));
+
+		if($isMarkerListingSubclass){
 			$map_id = $request['map_id'];
 			$instance = $class::createInstance($map_id);
 		} else {
 			$instance = $class::createInstance();
 		}
-		
+
 		if(!($instance instanceof DataTable))
 			return new \WP_Error('wpgmza_invalid_datatable_class', 'Specified PHP class must extend WPGMZA\\DataTable', array('status' => 403));

Exploit Outline

To exploit this vulnerability, an attacker sends a POST request to the `/wp-json/wpgmza/v1/datatables` endpoint. This specific route is explicitly exempted from nonce and authorization checks in the vulnerable versions. The attacker includes the `phpClass` parameter set to a CRUD-backed class such as `WPGMZA\Marker`, `WPGMZA\Map`, or `WPGMZA\Circle`. Along with the class name, the attacker provides the necessary database fields (e.g., `title`, `lat`, `lng`, `map_id`) in the request body. When the REST API controller instantiates the requested class via its factory pattern, the parent `CRUD` constructor identifies that no existing ID is present and automatically inserts the provided data into the corresponding database table. The record is committed even if the REST API eventually returns an error for other reasons.

Check if your site is affected.

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