Summary
The attachment AJAX handlers authorize the attachment being edited but not the caller-supplied target post. An Author can set an owned attachment’s post_parent to another user’s protected post.
Affected Products
WordPress core 7.0.4; Media Library AJAX handlers.
Affected Scope
- Product
- WordPress
- Component
- Media Library attachment AJAX
- Affected function
- wp_ajax_send_attachment_to_editor(); wp_ajax_save_attachment(); post_id; changes[parent]; post_parent
- Affected versions
- WordPress 7.0.4 (revalidated). Earlier/fixed versions are not asserted without a pinned vendor confirmation.
- Safe version
- No fixed version confirmed in the supplied material.
- CWE
- CWE-862; CWE-639
Technical Summary
The object-level authorization check covers the attachment source, not the target post that receives the relationship. The unchecked post_id/parent value reaches wp_update_post(post_parent).
Prerequisites and Permissions
Authenticated Author with edit permission on an owned attachment; a target post exists that the Author cannot edit.
Affected Locations
wp-admin/includes/ajax-actions.php: wp_ajax_send_attachment_to_editor() and wp_ajax_save_attachment(); post_id/changes[parent] → post_parent; equivalent target check in wp-admin/includes/media.php.
Reproducible Proof
A controlled Author request changed an owned attachment’s parent from 0 to an Administrator-owned private post, while a control using an unowned attachment was blocked.
Vulnerable Code
check_ajax_referer( &class="tok-comment">#39;media-send-to-editorclass="tok-string">39;, 39;nonce39; );
$attachment = wp_unslash( $_POST[&class="tok-comment">#39;attachment39;] );
$id = (int) $attachment[&class="tok-comment">#39;id39;];
$post = get_post( $id );
if ( current_user_can( &class="tok-comment">#39;edit_post39;, $id ) ) {
$insert_into_post_id = (int) $_POST[&class="tok-comment">#39;post_id39;];
if ( 0 === $post->post_parent && $insert_into_post_id ) {
wp_update_post(
array(
&class="tok-comment">#39;ID39; => $id,
&class="tok-comment">#39;post_parent39; => $insert_into_post_id,
)
);
}
}Severity
medium
Technical Analysis
wp_ajax_send_attachment_to_editor() checks current_user_can(edit_post, attachment_id), then accepts post_id and writes it as post_parent. wp_ajax_save_attachment() has the analogous changes[parent] path. Neither handler checks edit_post for the target post.
Impact
Integrity impact: an Author can alter relationships and media-library/editor metadata on a post they cannot edit, including a private or draft target. The post body is not modified and privilege escalation is not claimed.
Remediation
Check current_user_can(edit_post, target_post_id) before any post_parent write in both handlers; reject invalid/non-editable targets and add cross-user/private-post regression tests.
Timeline
- Published
- Advisory published
Credits
Reported by Aria Akhavan. Disclosure timeline: 2026-08-12 submission; 2026-09-07 follow-up; no response documented by 2026-09-14.