[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$ffYMtEVRB0Z__qtxw9zaLGBvbAyROVtFhMLrSsBDZlz8":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":26,"research_verified":27,"research_rounds_completed":28,"research_plan":29,"research_summary":30,"research_vulnerable_code":31,"research_fix_diff":32,"research_exploit_outline":33,"research_model_used":34,"research_started_at":35,"research_completed_at":36,"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":27,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":27,"source_links":37},"CVE-2026-4068","add-custom-fields-to-media-cross-site-request-forgery-to-custom-field-deletion-via-delete-parameter","Add Custom Fields to Media \u003C= 2.0.3 - Cross-Site Request Forgery to Custom Field Deletion via 'delete' Parameter","The Add Custom Fields to Media plugin for WordPress is vulnerable to Cross-Site Request Forgery in all versions up to, and including, 2.0.3. This is due to missing nonce validation on the field deletion functionality in the admin display template. The plugin properly validates a nonce for the 'add field' operation (line 24-36), but the 'delete field' operation (lines 38-49) processes the $_GET['delete'] parameter and calls update_option() without any nonce verification. This makes it possible for unauthenticated attackers to delete arbitrary custom media fields via a forged request, granted they can trick a site administrator into performing an action such as clicking on a link.","add-custom-fields-to-media",null,"\u003C=2.0.3","2.0.4","medium",4.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:R\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Cross-Site Request Forgery (CSRF)","2026-03-18 18:16:21","2026-03-19 06:46:13",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F259a4950-9377-4d18-86ad-aadd97dcdbc7?source=api-prod",1,[22,23,24,25],"README.txt","add-custom-fields-to-media.php","admin\u002Fpartials\u002Fadd-custom-fields-to-media-admin-display.php","includes\u002Fclass-add-custom-fields-to-media.php","researched",false,3,"# Exploitation Research Plan: CVE-2026-4068 - Add Custom Fields to Media CSRF\n\n## 1. Vulnerability Summary\nThe **Add Custom Fields to Media** plugin (\u003C= 2.0.3) contains a Cross-Site Request Forgery (CSRF) vulnerability in its administrative settings page. Specifically, the functionality to delete custom media fields does not perform any nonce validation or capability checks before modifying the site's configuration via `update_option()`. An attacker can trick a logged-in administrator into clicking a link that deletes defined custom fields, potentially disrupting site functionality or removing critical metadata.\n\n## 2. Attack Vector Analysis\n- **Vulnerable Endpoint**: `\u002Fwp-admin\u002Foptions-general.php?page=add-custom-fields-to-media`\n- **Hook**: Registered via `admin_menu` in the `Add_Custom_Fields_To_Media_Admin` class (referenced in `includes\u002Fclass-add-custom-fields-to-media.php`).\n- **HTTP Method**: `GET`\n- **Vulnerable Parameter**: `delete`\n- **Authentication Requirement**: Must be an authenticated user with `manage_options` capability (typically an Administrator).\n- **Preconditions**: At least one custom field must already exist in the `thisismyurl_custom_media_fields` option.\n\n## 3. Code Flow\n1.  The administrator visits the plugin's settings page: `wp-admin\u002Foptions-general.php?page=add-custom-fields-to-media`.\n2.  The file `admin\u002Fpartials\u002Fadd-custom-fields-to-media-admin-display.php` is loaded to render the UI.\n3.  On **Line 22**, a nonce is verified for the *addition* of fields, but it is stored in the `$nonce` variable:\n    ```php\n    $nonce = isset( $_REQUEST['_wpnonce'] ) ? wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'media_custom_fields_nonce' ) : false;\n    ```\n4.  On **Line 38**, the \"Delete field\" logic begins. It checks if `$_GET['delete']` is present and if `$media_custom_fields` is an array:\n    ```php\n    if ( ( isset( $_GET['delete'] ) && ! empty( $_GET['delete'] ) ) && is_array( $media_custom_fields ) ) {\n    ```\n5.  **Critically**, this block (Lines 38-49) **does not check the `$nonce` variable** or call `check_admin_referer()`.\n6.  The code iterates through existing fields, filters out the one matching `$_GET['delete']`, and updates the WordPress option:\n    ```php\n    update_option( 'thisismyurl_custom_media_fields', $new_custom_fields );\n    ```\n\n## 4. Nonce Acquisition Strategy\n**No nonce is required for this specific exploit.**\nThe vulnerability exists precisely because the `delete` operation fails to verify the nonce (`media_custom_fields_nonce`) that is otherwise used for the \"Add Field\" operation on the same page. The execution agent can proceed directly to the forgery.\n\n## 5. Exploitation Strategy\n### Step 1: Discover Target `unique_id`\nThe attacker needs to know the `unique_id` of the field they wish to delete. Since this is a CSRF attack, they can guess common IDs (like `copyright` or `author`) or target a specific ID if known.\n\n### Step 2: Forged Request\nThe exploit is a simple `GET` request. In a real-world scenario, this would be an `\u003Cimg>` tag or an auto-submitting form on an attacker-controlled site. For the PoC agent, a direct authenticated `http_request` to the target URL is sufficient.\n\n- **Request Type**: `GET`\n- **URL**: `http:\u002F\u002F[TARGET]\u002Fwp-admin\u002Foptions-general.php?page=add-custom-fields-to-media&delete=[FIELD_ID]`\n- **Headers**: Authentication cookies for an Administrator must be included.\n\n## 6. Test Data Setup\nBefore exploitation, we must ensure a custom field exists to be deleted.\n\n1.  **Create a field via WP-CLI**:\n    ```bash\n    wp option update thisismyurl_custom_media_fields '[{\"unique_id\":\"poc_field_to_delete\",\"name\":\"PoC Field\",\"help\":\"This will be deleted\"}]' --format=json\n    ```\n2.  **Verify the field exists**:\n    ```bash\n    wp option get thisismyurl_custom_media_fields\n    ```\n\n## 7. Expected Results\n- The HTTP request to the `delete` endpoint should return a `200 OK` status (as it loads the admin page).\n- The internal state of the WordPress database will change: the entry with `unique_id` \"poc_field_to_delete\" will be removed from the `thisismyurl_custom_media_fields` array.\n\n## 8. Verification Steps\nAfter performing the exploit with the `http_request` tool, run the following command to confirm the deletion:\n\n```bash\n# Check the option value. It should be an empty array or missing the poc_field_to_delete entry.\nwp option get thisismyurl_custom_media_fields --format=json\n```\nIf the exploit is successful, the output will NOT contain \"poc_field_to_delete\".\n\n## 9. Alternative Approaches\nIf the plugin logic requires the page to be re-rendered to confirm the deletion, we can navigate to the page using `browser_navigate` as an admin and then check the HTML for the absence of the field table:\n\n```javascript\n\u002F\u002F Using browser_eval to check if the field table contains our ID\nconst tableContent = document.body.innerHTML;\nconst isDeleted = !tableContent.includes('poc_field_to_delete');\nconsole.log(isDeleted);\n```\n\nHowever, since `update_option()` is called during the initial execution of the script when the `delete` parameter is present, a single GET request is technically sufficient to trigger the vulnerability.","The Add Custom Fields to Media plugin for WordPress is vulnerable to Cross-Site Request Forgery (CSRF) due to a lack of nonce validation on its field deletion functionality. An attacker can exploit this by tricking a site administrator into clicking a crafted link, which results in the deletion of custom media fields via the 'delete' GET parameter.","\u002F\u002F admin\u002Fpartials\u002Fadd-custom-fields-to-media-admin-display.php line 22\n$nonce = isset( $_REQUEST['_wpnonce'] ) ? wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'media_custom_fields_nonce' ) : false;\n\nif ( $nonce && isset( $_POST['unique_id'] ) && ! empty( $_POST['unique_id'] ) && isset( $_POST['field_title'] ) && ! empty( $_POST['field_title'] ) && isset( $_POST['field_help'] ) ) {\n\t\u002F\u002F Addition logic is protected by $nonce check above\n    \u002F\u002F ... (truncated)\n}\n\n\u002F\u002F admin\u002Fpartials\u002Fadd-custom-fields-to-media-admin-display.php line 38\nif ( ( isset( $_GET['delete'] ) && ! empty( $_GET['delete'] ) ) && is_array( $media_custom_fields ) ) {\n\tforeach ( $media_custom_fields as $check_for_delete ) {\n\t\tif ( urldecode( sanitize_text_field( wp_unslash( $_GET['delete'] ) ) ) !== $check_for_delete['unique_id'] ) {\n\t\t\t$new_custom_fields[] = array(\n\t\t\t\t'unique_id' => esc_attr( $check_for_delete['unique_id'] ),\n\t\t\t\t'name'      => esc_attr( $check_for_delete['name'] ),\n\t\t\t\t'help'      => esc_attr( $check_for_delete['help'] ),\n\t\t\t);\n\t\t}\n\t}\n\tupdate_option( 'thisismyurl_custom_media_fields', $new_custom_fields );\n}","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fadd-custom-fields-to-media\u002F2.0.3\u002Fadmin\u002Fpartials\u002Fadd-custom-fields-to-media-admin-display.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fadd-custom-fields-to-media\u002F2.0.4\u002Fadmin\u002Fpartials\u002Fadd-custom-fields-to-media-admin-display.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fadd-custom-fields-to-media\u002F2.0.3\u002Fadmin\u002Fpartials\u002Fadd-custom-fields-to-media-admin-display.php\t2025-06-29 19:26:34.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fadd-custom-fields-to-media\u002F2.0.4\u002Fadmin\u002Fpartials\u002Fadd-custom-fields-to-media-admin-display.php\t2026-03-13 00:20:38.000000000 +0000\n@@ -36,6 +36,10 @@\n }\n \n if ( ( isset( $_GET['delete'] ) && ! empty( $_GET['delete'] ) ) && is_array( $media_custom_fields ) ) {\n+\tif ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'acfm_delete_field' ) ) {\n+\t\twp_die( esc_html__( 'Security check failed.', 'add-custom-fields-to-media' ) );\n+\t}\n+\t$new_custom_fields = array();\n \tforeach ( $media_custom_fields as $check_for_delete ) {\n \t\tif ( urldecode( sanitize_text_field( wp_unslash( $_GET['delete'] ) ) ) !== $check_for_delete['unique_id'] ) {\n \t\t\t$new_custom_fields[] = array(\n@@ -69,7 +73,7 @@\n \t\t\t\t\t\t\u003Ctd>\u003C?php echo esc_html( $custom_field['unique_id'] ); ?>\u003C\u002Ftd>\n \t\t\t\t\t\t\u003Ctd>\u003C?php echo esc_html( $custom_field['name'] ); ?>\u003C\u002Ftd>\n \t\t\t\t\t\t\u003Ctd>\u003C?php echo esc_html( $custom_field['help'] ); ?>\u003C\u002Ftd>\n-\t\t\t\t\t\t\u003Ctd>\u003Ca href=\"\u003C?php echo esc_url( 'options-general.php?page=add-custom-fields-to-media&delete=' . $custom_field['unique_id'] ); ?>\" style=\"text-decoration: none;\" title=\"Delete Field\">\u003Cspan class=\"dashicons dashicons-trash\">\u003C\u002Fspan>\u003C\u002Fa>\u003C\u002Ftd>\n+\t\t\t\t\t\t\u003Ctd>\u003Ca href=\"\u003C?php echo esc_url( wp_nonce_url( 'options-general.php?page=add-custom-fields-to-media&delete=' . $custom_field['unique_id'], 'acfm_delete_field' ) ); ?>\" style=\"text-decoration: none;\" title=\"Delete Field\">\u003Cspan class=\"dashicons dashicons-trash\">\u003C\u002Fspan>\u003C\u002Fa>\u003C\u002Ftd>\n \t\t\t\t\t\u003C\u002Ftr>\n \t\t\t\t\u003C?php } ?>\n \t\t\t\u003C\u002Ftbody>","The exploit targets the plugin's settings page at `\u002Fwp-admin\u002Foptions-general.php?page=add-custom-fields-to-media`. An attacker identifies or guesses a custom field's 'unique_id' and crafts a GET request containing the 'delete' parameter set to that ID. Because the plugin logic in versions up to 2.0.3 fails to verify a nonce before calling update_option() to remove the field from the database, an authenticated administrator can be tricked (via social engineering or a malicious site) into triggering the deletion simply by visiting the crafted URL.","gemini-3-flash-preview","2026-04-18 02:24:08","2026-04-18 02:24:27",{"type":38,"vulnerable_version":39,"fixed_version":11,"vulnerable_browse":40,"vulnerable_zip":41,"fixed_browse":42,"fixed_zip":43,"all_tags":44},"plugin","2.0.3","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fadd-custom-fields-to-media\u002Ftags\u002F2.0.3","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fadd-custom-fields-to-media.2.0.3.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fadd-custom-fields-to-media\u002Ftags\u002F2.0.4","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fadd-custom-fields-to-media.2.0.4.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fadd-custom-fields-to-media\u002Ftags"]