Add Custom Fields to Media <= 2.0.3 - Cross-Site Request Forgery to Custom Field Deletion via 'delete' Parameter
Description
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.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:NTechnical Details
<=2.0.3What Changed in the Fix
Changes introduced in v2.0.4
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-4068 - Add Custom Fields to Media CSRF ## 1. Vulnerability Summary The **Add Custom Fields to Media** plugin (<= 2.0.3) contains a Cross-Site Request Forgery (CSRF) vulnerability in its administrative settings page. Specifically, the functionality to delete cu…
Show full research plan
Exploitation Research Plan: CVE-2026-4068 - Add Custom Fields to Media CSRF
1. Vulnerability Summary
The Add Custom Fields to Media plugin (<= 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.
2. Attack Vector Analysis
- Vulnerable Endpoint:
/wp-admin/options-general.php?page=add-custom-fields-to-media - Hook: Registered via
admin_menuin theAdd_Custom_Fields_To_Media_Adminclass (referenced inincludes/class-add-custom-fields-to-media.php). - HTTP Method:
GET - Vulnerable Parameter:
delete - Authentication Requirement: Must be an authenticated user with
manage_optionscapability (typically an Administrator). - Preconditions: At least one custom field must already exist in the
thisismyurl_custom_media_fieldsoption.
3. Code Flow
- The administrator visits the plugin's settings page:
wp-admin/options-general.php?page=add-custom-fields-to-media. - The file
admin/partials/add-custom-fields-to-media-admin-display.phpis loaded to render the UI. - On Line 22, a nonce is verified for the addition of fields, but it is stored in the
$noncevariable:$nonce = isset( $_REQUEST['_wpnonce'] ) ? wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'media_custom_fields_nonce' ) : false; - On Line 38, the "Delete field" logic begins. It checks if
$_GET['delete']is present and if$media_custom_fieldsis an array:if ( ( isset( $_GET['delete'] ) && ! empty( $_GET['delete'] ) ) && is_array( $media_custom_fields ) ) { - Critically, this block (Lines 38-49) does not check the
$noncevariable or callcheck_admin_referer(). - The code iterates through existing fields, filters out the one matching
$_GET['delete'], and updates the WordPress option:update_option( 'thisismyurl_custom_media_fields', $new_custom_fields );
4. Nonce Acquisition Strategy
No nonce is required for this specific exploit.
The 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.
5. Exploitation Strategy
Step 1: Discover Target unique_id
The 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.
Step 2: Forged Request
The exploit is a simple GET request. In a real-world scenario, this would be an <img> 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.
- Request Type:
GET - URL:
http://[TARGET]/wp-admin/options-general.php?page=add-custom-fields-to-media&delete=[FIELD_ID] - Headers: Authentication cookies for an Administrator must be included.
6. Test Data Setup
Before exploitation, we must ensure a custom field exists to be deleted.
- Create a field via WP-CLI:
wp option update thisismyurl_custom_media_fields '[{"unique_id":"poc_field_to_delete","name":"PoC Field","help":"This will be deleted"}]' --format=json - Verify the field exists:
wp option get thisismyurl_custom_media_fields
7. Expected Results
- The HTTP request to the
deleteendpoint should return a200 OKstatus (as it loads the admin page). - The internal state of the WordPress database will change: the entry with
unique_id"poc_field_to_delete" will be removed from thethisismyurl_custom_media_fieldsarray.
8. Verification Steps
After performing the exploit with the http_request tool, run the following command to confirm the deletion:
# Check the option value. It should be an empty array or missing the poc_field_to_delete entry.
wp option get thisismyurl_custom_media_fields --format=json
If the exploit is successful, the output will NOT contain "poc_field_to_delete".
9. Alternative Approaches
If 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:
// Using browser_eval to check if the field table contains our ID
const tableContent = document.body.innerHTML;
const isDeleted = !tableContent.includes('poc_field_to_delete');
console.log(isDeleted);
However, 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.
Summary
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.
Vulnerable Code
// admin/partials/add-custom-fields-to-media-admin-display.php line 22 $nonce = isset( $_REQUEST['_wpnonce'] ) ? wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'media_custom_fields_nonce' ) : false; if ( $nonce && isset( $_POST['unique_id'] ) && ! empty( $_POST['unique_id'] ) && isset( $_POST['field_title'] ) && ! empty( $_POST['field_title'] ) && isset( $_POST['field_help'] ) ) { // Addition logic is protected by $nonce check above // ... (truncated) } // admin/partials/add-custom-fields-to-media-admin-display.php line 38 if ( ( isset( $_GET['delete'] ) && ! empty( $_GET['delete'] ) ) && is_array( $media_custom_fields ) ) { foreach ( $media_custom_fields as $check_for_delete ) { if ( urldecode( sanitize_text_field( wp_unslash( $_GET['delete'] ) ) ) !== $check_for_delete['unique_id'] ) { $new_custom_fields[] = array( 'unique_id' => esc_attr( $check_for_delete['unique_id'] ), 'name' => esc_attr( $check_for_delete['name'] ), 'help' => esc_attr( $check_for_delete['help'] ), ); } } update_option( 'thisismyurl_custom_media_fields', $new_custom_fields ); }
Security Fix
@@ -36,6 +36,10 @@ } if ( ( isset( $_GET['delete'] ) && ! empty( $_GET['delete'] ) ) && is_array( $media_custom_fields ) ) { + if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'acfm_delete_field' ) ) { + wp_die( esc_html__( 'Security check failed.', 'add-custom-fields-to-media' ) ); + } + $new_custom_fields = array(); foreach ( $media_custom_fields as $check_for_delete ) { if ( urldecode( sanitize_text_field( wp_unslash( $_GET['delete'] ) ) ) !== $check_for_delete['unique_id'] ) { $new_custom_fields[] = array( @@ -69,7 +73,7 @@ <td><?php echo esc_html( $custom_field['unique_id'] ); ?></td> <td><?php echo esc_html( $custom_field['name'] ); ?></td> <td><?php echo esc_html( $custom_field['help'] ); ?></td> - <td><a href="<?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"><span class="dashicons dashicons-trash"></span></a></td> + <td><a href="<?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"><span class="dashicons dashicons-trash"></span></a></td> </tr> <?php } ?> </tbody>
Exploit Outline
The exploit targets the plugin's settings page at `/wp-admin/options-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.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.