Revive.so <= 2.0.7 - Missing Authorization
Description
The Revive.so plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 2.0.7. 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:L/A:NTechnical Details
What Changed in the Fix
Changes introduced in v2.0.8
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-39561 ## 1. Vulnerability Summary The **Revive.so** plugin (versions <= 2.0.7) contains a missing authorization vulnerability within its settings import logic. Specifically, the function `REVIVESO_Pro_Settings_Importer::import_settings()` is hooked to `admin_…
Show full research plan
Exploitation Research Plan - CVE-2026-39561
1. Vulnerability Summary
The Revive.so plugin (versions <= 2.0.7) contains a missing authorization vulnerability within its settings import logic. Specifically, the function REVIVESO_Pro_Settings_Importer::import_settings() is hooked to admin_init but lacks any capability checks (current_user_can) or CSRF protection (nonces).
Since admin_init is triggered when accessing administrative files like wp-admin/admin-post.php or wp-admin/admin-ajax.php—even by unauthenticated users—an attacker can force the plugin to overwrite its current configuration and social media credentials with data from the legacy "RevivePress" plugin options, if they exist in the database.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-post.php(or any admin page that triggersadmin_init). - HTTP Method:
GET - Vulnerable Parameter:
revs_import=revivepress - Authentication: Unauthenticated (None).
- Preconditions: The WordPress option
wpar_plugin_settingsmust exist in the database (simulating a prior installation of the RevivePress plugin).
3. Code Flow
- Entry Point: A request is made to
/wp-admin/admin-post.php?revs_import=revivepress. - Hook Execution: WordPress loads and triggers the
admin_inithook. - Target Function:
REVIVESO_Pro_Settings_Importer::import_settings()(registered inincludes/import/class-revive-import.phpviaadd_action( 'admin_init', array( $this, 'import_settings' ), 50 );) is executed. - Conditional Check: The function checks
get_option('wpar_plugin_settings')and if$_GET['revs_import'] == 'revivepress'. - Unauthorized Sink: If conditions are met, the function performs multiple
update_option()calls, including:update_option('reviveso_plugin_settings', ...)update_option('reviveso_social_credentials', ...)update_option('reviveso_facebook_accounts_db', ...)- Overwrites
reviveso_show_import_noticeto0.
- Termination: The function issues a
header("Location: ...")and callsexit().
4. Nonce Acquisition Strategy
No nonce is required.
The vulnerable function import_settings() in includes/import/class-revive-import.php does not implement check_admin_referer or any other nonce verification. It relies solely on the presence of the revs_import GET parameter.
5. Exploitation Strategy
The goal is to demonstrate that an unauthenticated request can modify plugin options.
Step-by-Step Plan:
- Setup: Use WP-CLI to seed the database with "RevivePress" settings to simulate an upgrade scenario.
- Execute Exploit: Use
http_requestto send an unauthenticated GET request to the target site. - Confirmation: Use WP-CLI to verify that the
reviveso_plugin_settingsoption now contains the data from the seededwpar_plugin_settings.
Payload (HTTP Request):
GET /wp-admin/admin-post.php?revs_import=revivepress HTTP/1.1
Host: TARGET_HOST
User-Agent: Mozilla/5.0
Connection: close
6. Test Data Setup
To trigger the vulnerable code path, the wpar_plugin_settings option must be present. Run the following via the agent's command line:
# Seed the source option (legacy plugin settings)
wp option add wpar_plugin_settings '{"wpar_test_key":"vulnerable_value"}' --format=json
# Ensure the destination option is either empty or different
wp option delete reviveso_plugin_settings || true
# Set the notice to shown (1) to verify it gets dismissed
wp option update reviveso_show_import_notice 1
7. Expected Results
- The HTTP request should return a
301or302redirect (to the login page or admin page). - The option
reviveso_plugin_settingswill be created/updated. - The key
reiveveso_test_key(note the typo in the source:reiveveso) will exist in the updated option with the value"vulnerable_value". - The option
reviveso_show_import_noticewill be changed to0.
8. Verification Steps
After sending the HTTP request, verify the changes using WP-CLI:
# Verify the settings were imported
wp option get reviveso_plugin_settings --format=json
# Verify the notice was dismissed
wp option get reviveso_show_import_notice
9. Alternative Approaches
If /wp-admin/admin-post.php is blocked or behaves unexpectedly, any other admin URL can be used as a trigger, as long as it fires admin_init:
/wp-admin/admin-ajax.php?revs_import=revivepress/wp-admin/index.php?revs_import=revivepress(Note: unauthenticated access toindex.phpwill usually redirect to login, butadmin_initmay still fire before the redirect logic in some configurations).
The most reliable unauthenticated triggers for admin_init are admin-post.php and admin-ajax.php.
Summary
The Revive.so plugin for WordPress (<= 2.0.7) is vulnerable to unauthorized settings modification because it lacks capability checks and CSRF protection on its settings import logic. An unauthenticated attacker can force the plugin to overwrite its configuration and social media credentials with data from legacy 'RevivePress' settings by triggering the `admin_init` hook via a specifically crafted request.
Vulnerable Code
// includes/import/class-revive-import.php:84 public function import_settings(){ $revivepress_settings = get_option('wpar_plugin_settings'); $action = ( isset( $_GET['revs_import'] ) && 'revivepress' == $_GET['revs_import'] ) ? true : false; $new_settings = array(); if( $revivepress_settings && $action ){ foreach( $revivepress_settings as $key => $setting ){ $new_key = str_replace('wpar', 'reiveveso', $key ); $new_settings[$new_key] = $setting; } update_option('reviveso_plugin_settings', $new_settings ); $social = get_option( 'wpar_social_credentials', false ); $facebook = get_option( 'wpar_facebook_accounts_db', false ); $linkedin = get_option( 'wpar_linkedin_accounts_db', false ); $pinterest = get_option( 'wpar_pinterest_accounts_db', false ); $twitter = get_option( 'wpar_twitter_accounts_db', false ); $tumblr = get_option( 'wpar_tumblr_accounts_db', false ); if( $social ){ update_option( 'reviveso_social_credentials', $social ); } if( $facebook ){ update_option( 'reviveso_facebook_accounts_db', $facebook ); } if( $linkedin ){ update_option( 'reviveso_linkedin_accounts_db', $linkedin ); } if( $pinterest ){ update_option( 'reviveso_pinterest_accounts_db', $pinterest ); } if( $twitter ){ update_option( 'reviveso_twitter_accounts_db', $twitter ); } if( $tumblr ){ update_option( 'reviveso_tumblr_accounts_db', $tumblr ); } update_option('reviveso_show_import_notice', 0 ); header("Location: " . add_query_arg( array( 'page' => 'reviveso'), admin_url('admin.php') ) , TRUE, 301); exit(); } }
Security Fix
@@ -32,7 +32,7 @@ $revivepress_settings = get_option( 'wpar_plugin_settings', false ); $import_notice = get_option( 'reviveso_show_import_notice', 1 ); - $url = add_query_arg( array( 'revs_import' => 'revivepress'), admin_url('admin.php') ); + $url = wp_nonce_url( add_query_arg( array( 'revs_import' => 'revivepress' ), admin_url( 'admin.php' ) ), 'reviveso_import_settings' ); if ( $revivepress_settings && $import_notice ) { if ( REVIVESO_Admin::is_reviveso_admin_page() ) { ?> @@ -81,12 +81,20 @@ } } - public function import_settings(){ - - $revivepress_settings = get_option('wpar_plugin_settings'); - $action = ( isset( $_GET['revs_import'] ) && 'revivepress' == $_GET['revs_import'] ) ? true : false; - $new_settings = array(); - if( $revivepress_settings && $action ){ + public function import_settings() { + + if ( ! current_user_can( 'manage_options' ) ) { + return; + } + + if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'reviveso_import_settings' ) ) { + return; + } + + $revivepress_settings = get_option( 'wpar_plugin_settings' ); + $action = ( isset( $_GET['revs_import'] ) && 'revivepress' === $_GET['revs_import'] ) ? true : false; + $new_settings = array(); + if ( $revivepress_settings && $action ) { foreach( $revivepress_settings as $key => $setting ){ $new_key = str_replace('wpar', 'reiveveso', $key );
Exploit Outline
An attacker sends an unauthenticated GET request to an administrative endpoint that triggers the admin_init hook (e.g., /wp-admin/admin-post.php?revs_import=revivepress). Because the vulnerable function lacks current_user_can() authorization and nonce verification, it proceeds to check for the existence of the 'wpar_plugin_settings' WordPress option. If present, the plugin automatically imports these legacy settings, overwriting the current Revive.so plugin configuration, social credentials for multiple platforms (Facebook, LinkedIn, etc.), and dismissing the import notice.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.