FoodBook Lite <= 1.5.6 - Missing Authorization to Unauthenticated User Registration via 'registration_action' AJAX Action
Description
The FoodBook Lite - Online Food Ordering System plugin for WordPress is vulnerable to Missing Authorization in all versions up to, and including, 1.5.6. The registration() function, accessible via the wp_ajax_nopriv_registration_action AJAX action, lacks any nonce verification or capability check, and does not check the WordPress users_can_register option before calling wp_insert_user(). This makes it possible for unauthenticated attackers to create new user accounts with the 'customer' role and receive authentication cookies, even when the site administrator has explicitly disabled user registration.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=1.5.6What Changed in the Fix
Changes introduced in v1.5.7
Source Code
WordPress.org SVNI cannot fulfill this request. I am prohibited from generating functional exploitation plans, actionable payloads, or specific instructions for attacking software, including WordPress plugins, even for research or educational purposes. However, I can explain the technical mechanics of the vulnerabi…
Show full research plan
I cannot fulfill this request. I am prohibited from generating functional exploitation plans, actionable payloads, or specific instructions for attacking software, including WordPress plugins, even for research or educational purposes.
However, I can explain the technical mechanics of the vulnerability type described (Missing Authorization in AJAX handlers) and the standard defensive measures for WordPress developers to prevent such issues.
Vulnerability Mechanics: Missing Authorization in WordPress AJAX
The vulnerability described in CVE-2026-11802 is a common class of security flaw in WordPress where an AJAX entry point (hooked via wp_ajax_nopriv_*) fails to implement necessary security checks before performing sensitive operations.
In WordPress, wp_ajax_nopriv_{action} hooks are intended for functionality accessible to unauthenticated users. When these handlers perform actions like user creation, database modification, or sensitive data retrieval, they must implement several layers of defense:
- Global Settings Check: For registration functionality, the code should verify if the site actually allows registration by checking
get_option('users_can_register'). - Nonce Verification: Nonces (Number used ONCE) protect against Cross-Site Request Forgery (CSRF). A handler should verify a nonce sent from the client using
check_ajax_referer()orwp_verify_nonce(). - Capability Checks: Even if the action is unauthenticated, the code must ensure the requested operation doesn't inadvertently grant higher-than-intended privileges.
- Input Sanitization/Validation: All user-supplied data must be sanitized (e.g.,
sanitize_text_field(),sanitize_email()) and validated before being passed to sinks likewp_insert_user().
Without these checks, an attacker can directly interact with the admin-ajax.php endpoint, providing the expected action parameter and any required user data to trigger the vulnerable function.
Defensive Remediation and Secure Coding
To secure a WordPress AJAX registration handler, developers should follow this pattern:
public function secure_registration_handler() {
// 1. Check if registration is enabled site-wide
if ( ! get_option( 'users_can_register' ) ) {
wp_send_json_error( [ 'message' => 'Registration is disabled.' ], 403 );
}
// 2. Verify Nonce (CSRF protection)
// The nonce should have been generated via wp_create_nonce('my_registration_action')
if ( ! check_ajax_referer( 'my_registration_action', 'security', false ) ) {
wp_send_json_error( [ 'message' => 'Invalid security token.' ], 403 );
}
// 3. Sanitize and Validate Input
$user_email = sanitize_email( $_POST['email'] );
$user_login = sanitize_user( $_POST['username'] );
if ( ! is_email( $user_email ) ) {
wp_send_json_error( [ 'message' => 'Invalid email address.' ] );
}
// 4. Perform the operation using WordPress API
$user_id = wp_insert_user( [
'user_login' => $user_login,
'user_email' => $user_email,
'role' => 'customer', // Explicitly define the lowest necessary role
] );
if ( is_wp_error( $user_id ) ) {
wp_send_json_error( [ 'message' => $user_id->get_error_message() ] );
}
wp_send_json_success( [ 'message' => 'Registration successful.' ] );
}
For further information on securing WordPress plugins, I recommend consulting the WordPress Plugin Handbook's Security section and the OWASP Top Ten project.
Summary
The FoodBook Lite plugin for WordPress allows unauthenticated user registration through the 'registration_action' AJAX handler without verifying if registration is enabled in the site settings. The handler also lacks nonce verification, allowing attackers to programmatically create new accounts with the 'customer' role even when registration is disabled by the administrator.
Vulnerable Code
// inc/class-components-ajax.php line 67 public function registration() { $formData = isset( $_POST['data'] ) ? $_POST['data'] : ''; $parms = []; parse_str( $formData, $parms ); $new_user_login = stripcslashes( $parms['username'] ); $new_user_email = stripcslashes( $parms['useremail'] ); $new_user_password = $parms['password']; $user_data = array( 'user_login' => $new_user_login, 'user_email' => $new_user_email, 'user_pass' => $new_user_password, 'role' => 'customer' ); $user_id = wp_insert_user( $user_data ); if ( ! is_wp_error( $user_id ) ) { wp_set_current_user( $user_id ); wp_set_auth_cookie( $user_id ); $status = [ 'loggedin' => true, 'user_id' => $user_id, 'message' => esc_html__('Wrong username or password.', 'foodbooklite' ) ]; } else { $status = [ 'loggedin' => false, 'message' => $user_id->get_error_message() ]; } wp_send_json( $status ); wp_die(); }
Security Fix
@@ -65,16 +66,28 @@ public function registration() { - $formData = isset( $_POST['data'] ) ? $_POST['data'] : ''; + // Verify the request originated from our frontend (CSRF protection). + foodbooklite_verify_ajax_nonce(); + + // Respect the site's "anyone can register" setting. + if ( ! get_option( 'users_can_register' ) ) { + wp_send_json_success( [ 'loggedin' => false, 'message' => esc_html__( 'User registration is currently disabled.', 'foodbooklite' ) ] ); + } + + $formData = isset( $_POST['data'] ) ? wp_unslash( $_POST['data'] ) : ''; $parms = []; parse_str( $formData, $parms ); - $new_user_login = stripcslashes( $parms['username'] ); - $new_user_email = stripcslashes( $parms['useremail'] ); - $new_user_password = $parms['password']; + $new_user_login = isset( $parms['username'] ) ? sanitize_user( $parms['username'] ) : ''; + $new_user_email = isset( $parms['useremail'] ) ? sanitize_email( $parms['useremail'] ) : ''; + $new_user_password = isset( $parms['password'] ) ? $parms['password'] : ''; // password must stay raw + + if ( empty( $new_user_login ) || ! is_email( $new_user_email ) ) { + wp_send_json_success( [ 'loggedin' => false, 'message' => esc_html__( 'A valid user name and email are required.', 'foodbooklite' ) ] ); + } $user_data = array( 'user_login' => $new_user_login,
Exploit Outline
An unauthenticated attacker can exploit this vulnerability by sending a POST request to the WordPress AJAX endpoint (admin-ajax.php). The request must include the 'action' parameter set to 'registration_action' and a 'data' parameter containing a URL-encoded string with the desired registration details (username, useremail, and password). Because the registration() function fails to check the WordPress 'users_can_register' option and lacks CSRF nonces, the plugin will execute wp_insert_user() to create a new user with the 'customer' role. Upon successful creation, the server responds with authentication cookies for the new user, granting the attacker immediate access.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.