On November 27th, 2025, we received a submission for a Site Reset and Privilege Escalation vulnerability in Demo Importer Plus, a WordPress plugin with more than 10,000 active installations. This vulnerability can be leveraged to trigger a full site reset and assign the administrator role to the attacker’s account.
Props to shark3y who discovered and responsibly reported this vulnerability through the Wordfence Bug Bounty Program. This researcher earned a bounty of $195.00 for this discovery. Our mission is to secure WordPress through defense in depth, which is why we are investing in quality vulnerability research and collaborating with researchers of this caliber through our Bug Bounty Program. We are committed to making the WordPress ecosystem more secure through the detection and prevention of vulnerabilities, which is a critical element to our multi-layered approach to security.
Wordfence Premium, Wordfence Care, and Wordfence Response users received a firewall rule to protect against any exploits targeting this vulnerability on December 10, 2025. Sites using the free version of Wordfence will receive the same protection 30 days later on January 9, 2026.
We provided full disclosure details to the Codewing Solutions team instantly through our Wordfence Vulnerability Management Portal on December 9, 2025. The vendor acknowledged the report and released the patch on December 16, 2025. We would like to commend the Codewing Solutions team for their prompt response and timely patch.
We urge users to update their sites with the latest patched version of Demo Importer Plus, version 2.0.9 at the time of this publication, as soon as possible.
Vulnerability Summary from Wordfence Intelligence
Technical Analysis
Examining the code reveals that the plugin uses the handle_request() function in the KraftPluginsDemoImporterPlusAjax class to handle AJAX actions, including the ‘do-reinstall’ action.
add_action( 'wp_ajax_demo_importer_plus', array( KraftPluginsDemoImporterPlusAjax::class, 'handle_request' ) ); add_action( 'wp_ajax_nopriv_demo_importer_plus', array( KraftPluginsDemoImporterPlusAjax::class, 'handle_request' ) );
class Ajax {
public static function handle_request() {
// Get Method.
$method = $_SERVER[ 'REQUEST_METHOD' ] ?? 'GET';
$request = new WP_REST_Request( $method );
if ( isset( $_SERVER[ 'HTTP_X_WP_NONCE' ] ) || isset( $_REQUEST[ '_nonce' ] ) ) {
$request->set_header( 'X-WP-Nonce', $_SERVER[ 'HTTP_X_WP_NONCE' ] ?? $_REQUEST[ '_nonce' ] );
if ( ! wp_verify_nonce( $request->get_header( 'x-wp-nonce' ), 'wp_rest' ) ) {
wp_send_json_error( 'Invalid Request', 403 );
}
$request->set_body( file_get_contents( 'php://input' ) );
$request->set_query_params( $_GET );
$request->set_header( 'Content-Type', 'application/json' );
$request->set_body_params( $_POST );
$demo_action = $request->get_param( 'demo_action' );
$data = array();
switch ( $demo_action ) {
case 'test-connection':
$data = static::test_server_connection( $request );
break;
case 'check-server-config':
$data = static::check_server_config( $request );
break;
case 'demos':
if ( $request->get_param( 'id' ) ) {
$data = static::get_demo_by_id( $request );
} else {
$data = static::get_demos( $request );
}
break;
case 'demo-categories':
$data = static::get_demo_categories( $request );
break;
break;
case 'import-demo':
if ( $request->get_param( 'id' ) ) {
$data = static::import_demo_site( $request );
} else {
$data = new WP_Error( 'invalid_request', 'Requires Demo ID.' );
}
break;
case 'update_attachment':
$data = static::update_attachment( $request );
break;
case 'required-plugins':
if ( $request->get_param( 'id' ) ) {
$data = static::get_required_plugins( $request );
} else {
$data = new WP_Error( 'invalid_request', 'Requires Demo ID.' );
}
break;
case 'import-page':
if ( $request->get_param( 'id' ) && $request->get_param( 'page_id' ) ) {
$data = static::import_page( $request );
} else {
$data = new WP_Error( 'invalid_request', 'Invalid Page ID and Demo ID.' );
}
break;
case 'do-reinstall':
$data = static::do_reinstall( $request );
break;
Although this function is protected with a nonce check, the nonce can be obtained by authenticated attackers, with minimal permissions such as subscribers. Additionally, there was no capability check in the vulnerable version. This makes it possible for authenticated attackers with subscriber-level permission to invoke the AJAX action and reinstall the site. After the reinstall, the current user (i.e., the attacker), would become the only administrator user.
Note: The plugin uses the commonly used ‘wp_rest’ nonce, therefore, if other plugins expose this nonce to unauthenticated users for their own functionality, this vulnerability can be exploited unauthenticated, since the ‘nopriv’ AJAX endpoint is also registered.
Once an attacker has gained administrative user access to a WordPress site they can then manipulate anything on the targeted site as a normal administrator would. This includes the ability to upload plugin and theme files, which can be malicious zip files containing backdoors, and modifying posts and pages which can be leveraged to redirect site users to other malicious sites.
The Patch
The vendor patched this issue by adding an administrator capability check to the ‘do-reinstall’ action in the handle_request() function.
case 'do-reinstall':
if ( ! current_user_can( 'manage_options' ) ) {
$data = new WP_Error( 'permission_denied', 'You do not have permission to reset site.', 403 );
} else {
$data = static::do_reinstall( $request );
}
break;
Disclosure Timeline
November 27, 2025 – We received the submission for the Site Reset and Privilege Escalation vulnerability in Demo Importer Plus via the Wordfence Bug Bounty Program.
December 9, 2025 – We validated the report and confirmed the proof-of-concept exploit.
December 9, 2025 – Full disclosure details were sent instantly to the vendor through our Wordfence Vulnerability Management Portal.
December 10, 2025 – Wordfence Premium, Care, and Response users received a firewall rule to provide added protection against any exploits that may target this vulnerability.
December 16, 2025 – The vendor acknowledged the report and began working on a fix.
December 16, 2025 – The fully patched version of the plugin, 2.0.9, was released.
January 9, 2026 – Wordfence Free users will receive the same protection.
Conclusion
In this blog post, we detailed a Site Reset and Privilege Escalation vulnerability within the Demo Importer Plus plugin affecting versions 2.0.8 and earlier. This vulnerability allows authenticated threat actors to reset the site and elevate their privileges to that of a site administrator. The vulnerability has been addressed in version 2.0.9 of the plugin.
We encourage WordPress users to verify that their sites are updated to the latest patched version of Demo Importer Plus as soon as possible considering the critical nature of this vulnerability.
Wordfence Premium, Wordfence Care, and Wordfence Response users received a firewall rule to protect against any exploits targeting this vulnerability on December 10, 2025. Sites using the free version of Wordfence will receive the same protection 30 days later on January 9, 2026.
If you know someone who uses this plugin on their site, we recommend sharing this advisory with them to ensure their site remains secure, as this vulnerability poses a significant risk.
The post 10,000 WordPress Sites Protected Against Site Reset and Privilege Escalation Vulnerability in Demo Importer Plus WordPress Plugin appeared first on Wordfence.