[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fxkL12FKYYDP70Vr8cPM7vJYhul5qYyYfABeUsUN8g5A":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":27,"research_verified":28,"research_rounds_completed":29,"research_plan":30,"research_summary":31,"research_vulnerable_code":32,"research_fix_diff":33,"research_exploit_outline":34,"research_model_used":35,"research_started_at":36,"research_completed_at":37,"research_error":9,"poc_status":38,"poc_video_id":9,"poc_summary":39,"poc_steps":40,"poc_tested_at":41,"poc_wp_version":42,"poc_php_version":43,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":44,"poc_model_used":9,"poc_verification_depth":9,"source_links":45},"CVE-2026-5436","mw-wp-form-unauthenticated-arbitrary-file-move-via-regenerateuploadfilekeys","MW WP Form \u003C= 5.1.1 - Unauthenticated Arbitrary File Move via regenerate_upload_file_keys","The MW WP Form plugin for WordPress is vulnerable to Arbitrary File Move\u002FRead in all versions up to and including 5.1.1. This is due to insufficient validation of the $name parameter (upload field key) passed to the generate_user_file_dirpath() function, which uses WordPress's path_join() — a function that returns absolute paths unchanged, discarding the intended base directory. The attacker-controlled key is injected via the mwf_upload_files[] POST parameter, which is loaded into the plugin's Data model via _set_request_valiables(). During form processing, regenerate_upload_file_keys() iterates over these keys and calls generate_user_filepath() with the attacker-supplied key as the $name argument — the key survives validation because the targeted file (e.g., wp-config.php) genuinely exists at the absolute path. The _get_attachments() method then re-reads the same surviving keys and passes the resolved file path to move_temp_file_to_upload_dir(), which calls rename() to move the file into the uploads folder. This makes it possible for unauthenticated attackers to move arbitrary files on the server, which can easily lead to remote code execution when the right file is moved (such as wp-config.php). The vulnerability is only exploitable if a file upload field is added to the form and the “Saving inquiry data in database” option is enabled.","mw-wp-form",null,"\u003C=5.1.1","5.1.2","high",8.1,"CVSS:3.1\u002FAV:N\u002FAC:H\u002FPR:N\u002FUI:N\u002FS:U\u002FC:H\u002FI:H\u002FA:H","Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')","2026-04-08 07:57:15","2026-04-15 13:45:06",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fbc308993-7fc5-41db-a396-f05e95fe47b8?source=api-prod",7,[22,23,24,25,26],"classes\u002Fcontrollers\u002Fclass.main.php","classes\u002Fmodels\u002Fclass.data.php","classes\u002Fmodels\u002Fclass.directory.php","mw-wp-form.php","readme.txt","researched",false,3,"This research plan outlines the exploitation of **CVE-2026-5436**, an unauthenticated arbitrary file move\u002Fread vulnerability in the **MW WP Form** plugin.\n\n### 1. Vulnerability Summary\nThe vulnerability exists due to improper path validation in `MW_WP_Form_Directory::generate_user_file_dirpath()`. The function uses WordPress's `path_join()` to combine a base temporary directory with a user-supplied directory name (`$name`). If `$name` is an absolute path, `path_join()` returns it unchanged, allowing an attacker to escape the intended directory.\n\nWhen a form is submitted, the plugin processes file attachments. If the \"Saving inquiry data in database\" option is enabled, it resolves the file paths and moves them from the temporary directory to the permanent uploads directory using `rename()`. By injecting an absolute path as the key in the `mwf_upload_files[]` parameter, an attacker can trick the plugin into moving arbitrary files (like `wp-config.php`) from their original location into the publicly accessible uploads folder.\n\n### 2. Attack Vector Analysis\n*   **Endpoint**: The main site frontend where an `mwform` shortcode is rendered.\n*   **Hook**: `template_redirect` (via `MW_WP_Form_Main_Controller::_template_redirect()`).\n*   **Vulnerable Parameter**: `mwf_upload_files[]` (an array where the key is the directory path and the value is the filename).\n*   **Authentication**: Unauthenticated.\n*   **Preconditions**:\n    1.  A form must exist with at least one file upload field.\n    2.  The \"Saving inquiry data in database\" option must be enabled for that form.\n    3.  The attacker must know the absolute path to the target file (standard WordPress installs use `\u002Fvar\u002Fwww\u002Fhtml\u002F`).\n\n### 3. Code Flow\n1.  **Request Entry**: `MW_WP_Form_Main_Controller::_template_redirect()` (Line 121, `class.main.php`) is called.\n2.  **Data Ingestion**: `MW_WP_Form_Data::connect()` (Line 144, `class.main.php`) is called, which triggers `_set_request_valiables()` (Line 183, `class.data.php`), loading all `$_POST` data (including the malicious `mwf_upload_files` array) into the `$this->variables` property.\n3.  **Condition Check**: If `$_POST['token']` is provided and no buttons are pressed, `get_post_condition()` returns `'complete'`.\n4.  **File Processing**: `_template_redirect` calls `_file_upload()` (Line 160, `class.main.php`), which calls `MWF_Functions::regenerate_upload_file_keys()`.\n5.  **Path Resolution**: `regenerate_upload_file_keys` calls `MW_WP_Form_Directory::generate_user_filepath($form_id, $name, $filename)`.\n6.  **Traversal Sink**: `generate_user_file_dirpath($form_id, $name)` (Line 64, `class.directory.php`) calls `path_join($user_dir, $name)`. If `$name` is `\u002Fvar\u002Fwww\u002Fhtml\u002F`, it returns `\u002Fvar\u002Fwww\u002Fhtml\u002F`.\n7.  **Validation Bypass**: `generate_user_filepath` (Line 150) checks `is_dir($user_file_dir)`. Since `\u002Fvar\u002Fwww\u002Fhtml\u002F` exists, it proceeds. The final path becomes `\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-config.php`.\n8.  **The Move**: `MW_WP_Form_Main_Controller::_send()` (Line 245, `class.main.php`) identifies that database saving is enabled (`usedb`). It calls `MWF_Functions::move_temp_file_to_upload_dir()`, which executes `rename('\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-config.php', '...\u002Fwp-content\u002Fuploads\u002Fmw-wp-form_uploads\u002F...')`.\n\n### 4. Nonce Acquisition Strategy\nThe plugin uses a custom CSRF token implementation (`MW_WP_Form_Csrf`). The token is required for the `_template_redirect` logic to proceed.\n\n1.  **Identify Form**: Find a page containing a form generated by the plugin.\n2.  **Navigate**: Use `browser_navigate` to that page.\n3.  **Extract**: The token is stored in a hidden input field named `token`.\n    *   **JS Command**: `browser_eval(\"document.querySelector('input[name=token]').value\")`.\n4.  **Form ID**: Extract the form ID from the hidden field `mw-wp-form-form-id`.\n    *   **JS Command**: `browser_eval(\"document.querySelector('input[name=\\\"mw-wp-form-form-id\\\"]').value\")`.\n\n### 5. Test Data Setup\n1.  **Create Form**: Create a new `mw-wp-form` post.\n    *   `wp post create --post_type=mw-wp-form --post_title=\"Vuln Form\" --post_status=publish`\n2.  **Configure Form**:\n    *   Add a file field: `[mwform_file name=\"upload_field\"]`.\n    *   Enable Database storage: `wp post meta update [FORM_ID] usedb 1`.\n3.  **Publish Page**: Place the form shortcode on a public page.\n    *   `wp post create --post_type=page --post_title=\"Contact\" --post_status=publish --post_content='[mwform_formkey key=\"[FORM_ID]\"]'`\n\n### 6. Exploitation Strategy\nPerform an unauthenticated HTTP POST request to the page where the form is hosted.\n\n*   **URL**: `http:\u002F\u002Flocalhost:8080\u002Fcontact\u002F`\n*   **Method**: `POST`\n*   **Headers**: `Content-Type: application\u002Fx-www-form-urlencoded`\n*   **Body Parameters**:\n    *   `mw-wp-form-form-id`: `[FORM_ID]`\n    *   `token`: `[EXTRACTED_TOKEN]`\n    *   `mwf_upload_files[\u002Fvar\u002Fwww\u002Fhtml\u002F]`: `wp-config.php`\n    *   `upload_field`: (Leave empty, or provide dummy value if required by validation)\n\n### 7. Expected Results\n1.  The plugin will process the request and treat `\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-config.php` as an uploaded attachment.\n2.  The file `wp-config.php` will be **moved** (deleted from root, moved to uploads).\n3.  The moved file will be located at: `http:\u002F\u002Flocalhost:8080\u002Fwp-content\u002Fuploads\u002Fmw-wp-form_uploads\u002F[PATH_TO_FILE]`\n    *   The path typically follows the structure: `mw-wp-form_uploads\u002F[TOKEN]\u002F[FORM_ID]\u002F[ENCODED_KEY]\u002Fwp-config.php`.\n    *   In version 5.0+, the filename might be renamed to something like `\u002Fvar\u002Fwww\u002Fhtml\u002F-wp-config.php`.\n\n### 8. Verification Steps\n1.  **Confirm Move**: Use WP-CLI to check if the site is broken (since `wp-config.php` is gone).\n    *   `ls \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-config.php` (Should return \"No such file\").\n2.  **Locate Target**: Check the uploads directory for the moved file.\n    *   `find \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fuploads\u002Fmw-wp-form_uploads\u002F -name \"*wp-config.php*\"`\n3.  **Read Secrets**: Cat the moved file to prove it was successfully read\u002Fmoved.\n\n### 9. Alternative Approaches\nIf the absolute path `\u002Fvar\u002Fwww\u002Fhtml\u002F` is incorrect:\n*   Use `mwf_upload_files[..\u002F]=wp-config.php` to attempt relative traversal if the temporary directory depth is known.\n*   If `wp-config.php` is protected by `rename()` permissions, attempt to move `\u002Fetc\u002Fpasswd` to a world-readable directory.\n*   If the \"complete\" condition is hard to trigger, attempt to trigger the \"confirm\" condition (`mwf_confirm_button=1`), which also calls `_file_upload()` and might move files to a temporary location that can still be guessed.","MW WP Form is vulnerable to unauthenticated arbitrary file move because it improperly handles file path generation for uploaded attachments. By supplying an absolute path as a key in the `mwf_upload_files` parameter, an attacker can exploit the behavior of WordPress's `path_join()` to bypass intended directory restrictions and move sensitive files like `wp-config.php` into a publicly accessible directory.","\u002F\u002F classes\u002Fmodels\u002Fclass.directory.php line 63\npublic static function generate_user_file_dirpath( $form_id, $name ) {\n\t$user_dir      = static::generate_user_dirpath( $form_id );\n\t$user_file_dir = path_join( $user_dir, $name );\n\n\treturn $user_file_dir;\n}\n\n---\n\n\u002F\u002F classes\u002Fmodels\u002Fclass.directory.php line 147\npublic static function generate_user_filepath( $form_id, $name, $filename ) {\n\tif ( ! $filename ) {\n\t\treturn false;\n\t}\n\n\t$user_file_dir = static::generate_user_file_dirpath( $form_id, $name );\n\tif ( ! $user_file_dir || ! is_dir( $user_file_dir ) ) {\n\t\treturn false;\n\t}\n\t\u002F\u002F ... validation ...\n\t$filepath      = path_join( $user_file_dir, $filename );","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fmw-wp-form\u002F5.1.1\u002Fclasses\u002Fmodels\u002Fclass.directory.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fmw-wp-form\u002F5.1.2\u002Fclasses\u002Fmodels\u002Fclass.directory.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fmw-wp-form\u002F5.1.1\u002Fclasses\u002Fmodels\u002Fclass.directory.php\t2026-03-26 10:37:14.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fmw-wp-form\u002F5.1.2\u002Fclasses\u002Fmodels\u002Fclass.directory.php\t2026-04-08 02:35:24.000000000 +0000\n@@ -54,9 +58,17 @@\n \t * @throws \\RuntimeException When directory name is not token value.\n \t *\u002F\n \tpublic static function generate_user_file_dirpath( $form_id, $name ) {\n+\t\tif ( ! static::_is_valid_path_segment( $name ) ) {\n+\t\t\tthrow new \\RuntimeException( '[MW WP Form] Invalid file reference requested.' );\n+\t\t}\n+\n \t\t$user_dir      = static::generate_user_dirpath( $form_id );\n \t\t$user_file_dir = path_join( $user_dir, $name );\n \n+\t\tif ( ! static::_is_within_expected_dir_candidate( $form_id, $user_file_dir ) ) {\n+\t\t\tthrow new \\RuntimeException( '[MW WP Form] Invalid file reference requested.' );\n+\t\t}\n+\n \t\treturn $user_file_dir;\n \t}","The exploit targets forms that have at least one file upload field and the 'Saving inquiry data in database' option enabled. \n\n1. Identify a target form and retrieve the required `mw-wp-form-form-id` and the CSRF `token` from the hidden input fields on the page.\n2. Construct a POST request to the form's endpoint (the URL where the shortcode is rendered).\n3. Inject a malicious absolute path via the `mwf_upload_files` array parameter. The key should be the absolute directory path of the target file, and the value should be the filename. For example: `mwf_upload_files[\u002Fvar\u002Fwww\u002Fhtml\u002F]=wp-config.php`.\n4. When the plugin processes the form, `generate_user_file_dirpath` uses `path_join()` with the absolute path key. Because `path_join()` returns absolute paths unchanged, the plugin treats the server's root or installation directory as the temporary upload folder.\n5. The plugin validates that the directory exists and then identifies the target file (e.g., `wp-config.php`) as a 'surviving' attachment from a previous (simulated) step.\n6. During the final processing stage (`_send`), the plugin calls `rename()` to move the target file from its original location into the public `wp-content\u002Fuploads\u002Fmw-wp-form_uploads\u002F` directory.\n7. The attacker can then access the moved file directly via its new URL to leak sensitive configuration data.","gemini-3-flash-preview","2026-04-16 16:29:52","2026-04-16 16:30:31","failed","All models in the chain (gemini-3-flash-preview, claude-opus-4-7) failed to produce a verified exploit.",[],"2026-04-17 18:36:19","6.7","8.3",true,{"type":46,"vulnerable_version":47,"fixed_version":11,"vulnerable_browse":48,"vulnerable_zip":49,"fixed_browse":50,"fixed_zip":51,"all_tags":52},"plugin","5.1.1","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fmw-wp-form\u002Ftags\u002F5.1.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fmw-wp-form.5.1.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fmw-wp-form\u002Ftags\u002F5.1.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fmw-wp-form.5.1.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fmw-wp-form\u002Ftags"]