Summary
The supplied chain combines four low-privilege disclosure paths: approved-comment PII to a Subscriber, user_login enumeration to a Contributor, unpublished-post title enumeration to an Author, and private attachment/file disclosure to an Author. Together they can expose private content and identity data; self-registration and each capability or configuration are prerequisites.
Affected Products
WordPress core legacy XML-RPC and admin-ajax handlers. The readable vulnerability package documents the component behavior against WordPress 7.0.3; the August 12 disclosure states that the findings were revalidated against 7.0.4, but the readable chain artifact does not include a complete 7.0.4 execution trace. Exact 7.0.4 status remains vendor-confirmation pending.
Affected Scope
- Product
- WordPress
- Component
- Legacy XML-RPC and admin-ajax disclosure handlers
- Affected function
- WP_XMLRPC_Server::wp_getComments(); wp_getAuthors(); wp_getMediaItem(); wp_getMediaLibrary(); wp_ajax_find_posts(); wp_ajax_get_attachment(); wp_ajax_query_attachments()
- Affected versions
- WordPress 7.0.3 per the readable supplied chain package; 7.0.4 revalidation is stated in the August 12 disclosure but is not independently traceable in the readable artifact
- Safe version
- Not established; vendor fix confirmation pending
- CWE
- CWE-639; CWE-200; CWE-284
Technical Summary
Low-privileged authenticated users can compose multiple legacy-handler disclosures to enumerate private posts, user logins, commenter PII, and private attachments or files.
Prerequisites and Permissions
Subscriber for the approved-comment PII path; Contributor or Author for the user-login, unpublished-post, and media paths as described in the component reports; XML-RPC and admin-ajax enabled; relevant non-public posts, comments, and attachments exist; direct uploads URLs serve files.
Affected Locations
wp-includes/class-wp-xmlrpc-server.php:3318 wp_getAuthors; :3661 wp_getComments; :4388 wp_getMediaItem; :4444 wp_getMediaLibrary. wp-admin/includes/ajax-actions.php:2247 wp_ajax_find_posts; :3011 wp_ajax_get_attachment; :3029 wp_ajax_query_attachments. Inputs include XML-RPC status=approve, attachment IDs, the find_posts nonce and search, and media query parameters.
Reproducible Proof
The supplied component reports record: a Subscriber response containing commenter email and IP; a Contributor or Author response containing administrator user_login; Author find_posts output containing other users private, draft, and pending titles; and Author media output containing private attachment metadata and a direct URL followed by a 200 file response. Full dump automation and bulk extraction are withheld.
Vulnerable Code
class="tok-comment">// wp-includes/class-wp-xmlrpc-server.php — wp_getComments()
$status = $struct[&class="tok-comment">#39;statusclass="tok-string">39;] ?? 39;39;;
if ( ! current_user_can( &class="tok-comment">#39;moderate_commentsclass="tok-string">39; ) && 39;approve39; !== $status ) {
return new IXR_Error( 401, __( &class="tok-comment">#39;Invalid comment status.39; ) );
}
...
$comments_struct[] = $this->_prepare_comment( $comment );
class="tok-comment">// wp-admin/includes/ajax-actions.php — wp_ajax_find_posts()
check_ajax_referer( &class="tok-comment">#39;find-posts39; );
...
$args = array(
&class="tok-comment">#39;post_type39; => array_keys( $post_types ),
&class="tok-comment">#39;post_statusclass="tok-string">39; => 39;any39;,
&class="tok-comment">#39;posts_per_page39; => 50,
);
...
$posts = get_posts( $args );
class="tok-comment">// wp-includes/class-wp-xmlrpc-server.php — wp_getAuthors()
foreach ( get_users( array( &class="tok-comment">#39;fieldsclass="tok-string">39; => array( 39;IDclass="tok-string">39;, 39;user_loginclass="tok-string">39;, 39;display_name39; ) ) ) as $user ) {
$authors[] = array(
&class="tok-comment">#39;user_id39; => $user->ID,
&class="tok-comment">#39;user_login39; => $user->user_login,
&class="tok-comment">#39;display_name39; => $user->display_name,
);
}Severity
high
Technical Analysis
The chain crosses legacy handler surfaces with missing object-level authorization. The comments path accepts status=approve for a low-privilege caller and passes each result to _prepare_comment, which includes author_email and author_ip fields in the supplied report. The authors path returns user_login for every account. The find_posts path uses a valid author nonce but queries post_status=any without author scope. Media reads gate on upload_files and fetch by caller-controlled attachment ID, exposing metadata and a direct uploads URL. Each component bypasses a stronger REST object-level check; the chain composes the resulting disclosure primitives.
Impact
Confidentiality: High when the required low-privilege accounts, non-public posts or comments, and relevant attachments exist. The combined result can expose commenter PII, account identifiers, unpublished post titles, and private attachment metadata or file contents. Integrity: Not demonstrated. Availability: Not demonstrated. The chain depends on the listed roles, enabled legacy handlers, and the site serving the relevant uploads URLs.
Remediation
Apply object-level check_read_permission and current_user_can(read_post) checks on every returned post, comment, and attachment. Scope find_posts queries to the caller and intended editorial context. Redact author_email, author_ip, and user_login from low-privilege responses. Enforce private-file authorization at the storage or web-server layer rather than relying on attachment metadata checks. Add cross-surface regression tests for XML-RPC status filters, author scoping, attachment IDs, and direct file retrieval.
Timeline
- Published
- Advisory published
Credits
Aria Akhavan / Haikhavan Security