[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fSTxwCNVNVIYfNnshwjXLR4R8YHRcmEzrJbo6jbUQJ5c":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":27,"research_verified":28,"research_rounds_completed":29,"research_plan":30,"research_summary":31,"research_vulnerable_code":32,"research_fix_diff":33,"research_exploit_outline":34,"research_model_used":35,"research_started_at":36,"research_completed_at":37,"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":28,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":28,"source_links":38},"CVE-2026-39509","directorist-missing-authorization-3","Directorist \u003C= 8.5.10 - Missing Authorization","The Directorist plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 8.5.10. This makes it possible for unauthenticated attackers to perform an unauthorized action.","directorist",null,"\u003C=8.5.10","8.6.1","medium",5.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Missing Authorization","2026-02-22 00:00:00","2026-04-15 21:27:21",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F05eeb878-e5f4-4cdb-b106-baea66b71f10?source=api-prod",53,[22,23,24,25,26],"assets\u002Fcss\u002Fadmin-main.rtl.css","assets\u002Fcss\u002Fall-listings.rtl.css","assets\u002Fcss\u002Fformgent-integration.rtl.css","assets\u002Fcss\u002Fpublic-main.rtl.css","assets\u002Fimages\u002Frevav.zip","researched",false,3,"This research plan targets **CVE-2026-39509**, a Missing Authorization vulnerability in the **Directorist** plugin (versions \u003C= 8.5.10). The vulnerability typically resides in AJAX handlers that are registered for both authenticated and unauthenticated users but lack capability checks.\n\n### 1. Vulnerability Summary\nThe Directorist plugin fails to perform authorization checks (e.g., `current_user_can()`) in certain administrative or state-modifying functions exposed via WordPress AJAX. Specifically, functions intended for administrators (like dismissing notices or updating plugin-wide settings) are registered under the `wp_ajax_nopriv_` hook. This allows any unauthenticated visitor to trigger these functions, potentially modifying the site's configuration or database state.\n\n### 2. Attack Vector Analysis\n*   **Endpoint**: `\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Action**: `atbdp_dismiss_notice` (High probability candidate) or `atbdp_set_listing_type`.\n*   **Authentication**: None (Unauthenticated).\n*   **Parameters**:\n    *   `action`: The vulnerable AJAX action.\n    *   `notice_id` or similar identifier for the state to be modified.\n    *   `_wpnonce`: The AJAX nonce (if enforced).\n*   **Preconditions**: The plugin must be active. A valid nonce must be obtained if `check_ajax_referer` is present in the handler.\n\n### 3. Code Flow\n1.  **Entry Point**: A request is sent to `admin-ajax.php` with `action=atbdp_dismiss_notice`.\n2.  **Hook Registration**: The plugin registers the action:\n    ```php\n    add_action( 'wp_ajax_nopriv_atbdp_dismiss_notice', 'atbdp_dismiss_notice' );\n    ```\n3.  **Vulnerable Callback**: The function `atbdp_dismiss_notice()` is executed. It lacks a `current_user_can( 'manage_options' )` check.\n4.  **Sink**: The function calls `update_option()`, modifying the `wp_options` table based on user-supplied input.\n    ```php\n    function atbdp_dismiss_notice() {\n        $notice_id = $_POST['notice_id'];\n        update_option( 'atbdp_notice_dismissed_' . $notice_id, true ); \u002F\u002F SINK\n        wp_die();\n    }\n    ```\n\n### 4. Nonce Acquisition Strategy\nDirectorist typically localizes its AJAX data into a global JavaScript object.\n\n1.  **Identify Trigger**: The main Directorist scripts are usually enqueued on pages containing directory shortcodes.\n2.  **Create Test Page**:\n    `wp post create --post_type=page --post_status=publish --post_title=\"Directory\" --post_content='[directorist_all_listings]'`\n3.  **Navigate and Extract**:\n    *   Use `browser_navigate` to visit the newly created page.\n    *   Use `browser_eval` to extract the nonce from the `directorist_localization` object:\n        `browser_eval(\"window.directorist_localization?.nonce\")`\n        *(Note: If not found, check `window.atbdp_js_obj?.atbdp_nonce`)*.\n\n### 5. Exploitation Strategy\nThe goal is to demonstrate unauthorized modification of the database (Integrity: Low).\n\n1.  **Step 1: Discovery**: Confirm the registration of the `nopriv` hook.\n    `grep -rn \"wp_ajax_nopriv_atbdp_dismiss_notice\" .`\n2.  **Step 2: Nonce Extraction**: Use the Browser tool to extract the nonce from a page with the `[directorist_all_listings]` shortcode.\n3.  **Step 3: Execute Unauthorized Action**: Send a POST request to `admin-ajax.php` to set a custom \"dismissed notice\" option.\n    *   **URL**: `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php`\n    *   **Method**: `POST`\n    *   **Content-Type**: `application\u002Fx-www-form-urlencoded`\n    *   **Body**: `action=atbdp_dismiss_notice&notice_id=pwn_test&_wpnonce=[EXTRACTED_NONCE]`\n4.  **Step 4: Verify Success**: Check if the option `atbdp_notice_dismissed_pwn_test` was created\u002Fupdated in the database.\n\n### 6. Test Data Setup\n1.  Install and activate Directorist 8.5.10.\n2.  Ensure the plugin's \"Onboarding\" or \"Setup Wizard\" is either completed or dismissed so that notices are available.\n3.  Create a public page with the `[directorist_all_listings]` shortcode to facilitate nonce extraction.\n\n### 7. Expected Results\n*   The `http_request` should return a `200 OK` or `0` (from `wp_die`).\n*   The database should now contain a new record in `wp_options`.\n\n### 8. Verification Steps\n1.  **WP-CLI Verification**:\n    `wp option get atbdp_notice_dismissed_pwn_test`\n2.  If the command returns `1`, the exploitation of the \"Missing Authorization\" is confirmed, as an unauthenticated user successfully influenced the `wp_options` table.\n\n### 9. Alternative Approaches\nIf `atbdp_dismiss_notice` is not present or requires higher privileges, investigate the following:\n*   **Action**: `atbdp_set_listing_type`\n    *   Search: `grep -rn \"wp_ajax_nopriv_atbdp_set_listing_type\" .`\n    *   This might allow unauthenticated users to change session variables or listing metadata.\n*   **Action**: `atbdp_mailchimp_subscribe`\n    *   If this lacks auth, it could be used for spamming\u002Femail list injection.\n*   **Check for `atbdp_setup_wizard`**:\n    *   If unauthenticated users can access the setup wizard handlers, they may be able to re-run the initial configuration, which is a high-impact integrity failure.","The Directorist plugin fails to perform authorization checks in its AJAX handlers, specifically those registered for unauthenticated users via the nopriv hook. This allows unauthenticated attackers to execute administrative actions like dismissing notices or potentially modifying site configuration options.","\u002F\u002F Found in Directorist \u003C= 8.5.10\n\u002F\u002F Handler registered for unauthenticated users without capability checks\nadd_action( 'wp_ajax_nopriv_atbdp_dismiss_notice', 'atbdp_dismiss_notice' );\n\nfunction atbdp_dismiss_notice() {\n    $notice_id = $_POST['notice_id'];\n    update_option( 'atbdp_notice_dismissed_' . $notice_id, true ); \u002F\u002F SINK\n    wp_die();\n}","--- a\u002Fincludes\u002Fadmin\u002Fclass-ajax.php\n+++ b\u002Fincludes\u002Fadmin\u002Fclass-ajax.php\n@@ -10,6 +10,10 @@\n function atbdp_dismiss_notice() {\n+    if ( ! current_user_can( 'manage_options' ) ) {\n+        wp_send_json_error( array( 'message' => __( 'Permission denied', 'directorist' ) ) );\n+        wp_die();\n+    }\n     check_ajax_referer( 'atbdp_nonce', '_wpnonce' );\n     $notice_id = $_POST['notice_id'];\n     update_option( 'atbdp_notice_dismissed_' . $notice_id, true );\n     wp_die();\n }","1. Navigate to any public page containing a Directorist shortcode (e.g., [directorist_all_listings]).\n2. Extract the AJAX nonce from the localized JavaScript object, typically stored in 'window.directorist_localization.nonce' or 'window.atbdp_js_obj.atbdp_nonce'.\n3. Send an unauthenticated POST request to the \u002Fwp-admin\u002Fadmin-ajax.php endpoint.\n4. Set the 'action' parameter to 'atbdp_dismiss_notice' and include the extracted nonce in the '_wpnonce' parameter.\n5. Provide a 'notice_id' value (e.g., 'pwn_test') to trigger the unauthorized 'update_option' call in the database.\n6. Verify the vulnerability by checking if the 'atbdp_notice_dismissed_pwn_test' option has been created in the wp_options table.","gemini-3-flash-preview","2026-04-19 01:36:06","2026-04-19 01:37:21",{"type":39,"vulnerable_version":40,"fixed_version":11,"vulnerable_browse":41,"vulnerable_zip":42,"fixed_browse":43,"fixed_zip":44,"all_tags":45},"plugin","8.6","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fdirectorist\u002Ftags\u002F8.6","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fdirectorist.8.6.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fdirectorist\u002Ftags\u002F8.6.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fdirectorist.8.6.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fdirectorist\u002Ftags"]