Pie Register – User Registration, Profiles & Content Restriction < 3.8.4.10 - Missing Authorization
Description
The Pie Register – User Registration, Profiles & Content Restriction plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to 3.8.4.10 (exclusive). This makes it possible for unauthenticated attackers to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<3.8.4.10What Changed in the Fix
Changes introduced in v3.8.4.10
Source Code
WordPress.org SVNThis research plan focuses on **CVE-2026-10530** (Missing Authorization) in the **Pie Register** plugin for WordPress. Based on the provided source code and vulnerability metadata, the flaw exists in an unauthenticated AJAX handler that allows attackers to modify plugin settings or form configuratio…
Show full research plan
This research plan focuses on CVE-2026-10530 (Missing Authorization) in the Pie Register plugin for WordPress. Based on the provided source code and vulnerability metadata, the flaw exists in an unauthenticated AJAX handler that allows attackers to modify plugin settings or form configurations due to a lack of capability checks.
Exploitation Research Plan: CVE-2026-10530
1. Vulnerability Summary
- Vulnerability: Missing Authorization (CWE-862).
- Plugin: Pie Register – User Registration, Profiles & Content Restriction.
- Affected Versions: < 3.8.4.10.
- Description: The plugin registers AJAX handlers (likely
pie_register_update_field_orderor similar settings-related actions) to thewp_ajax_nopriv_hook. These handlers fail to verify if the requesting user has administrative privileges (e.g.,manage_options) before performing sensitive operations likeupdate_option(). This allows unauthenticated users to corrupt form configurations or reset plugin settings.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php. - Action:
pie_register_update_field_order(Inferred based on plugin architecture and thegetCurrentFieldslogic inclasses/base.php). - Payload Parameter:
field_order(array) andform_id. - Authentication: None (Unauthenticated).
- Preconditions: The plugin must be active. A valid nonce may be required if the handler calls
check_ajax_referer().
3. Code Flow
- Entry Point: An unauthenticated request is sent to
admin-ajax.phpwithaction=pie_register_update_field_order. - Hook Registration: In
pie-register.php, thepieActions()method (called in__construct) registers the action:add_action('wp_ajax_nopriv_pie_register_update_field_order', array($this, 'pie_register_update_field_order')); - Vulnerable Function: The
pie_register_update_field_orderfunction (inferred) is executed. - Missing Check: The function retrieves
$_POST['field_order']and$_POST['form_id']. It fails to callcurrent_user_can('manage_options'). - Sink: The function calls
update_option("piereg_form_fields_" . intval($_POST['form_id']), $sanitized_data). - Impact: The
piereg_form_fields_option is overwritten, effectively reordering, deleting, or corrupting the registration form fields.
4. Nonce Acquisition Strategy
Pie Register localizes security tokens for its AJAX actions. These are typically exposed to the frontend when a registration form is rendered.
- Identify Trigger: The shortcode
[pie_register_form]enqueues the necessary scripts and localizes thepie_pr_dec_vars_arrayobject. - Setup: Create a public page containing the shortcode:
wp post create --post_type=page --post_status=publish --post_content='[pie_register_form]' - Extraction:
- Navigate to the newly created page using
browser_navigate. - Execute the following via
browser_eval:window.pie_pr_dec_vars_array?.ajax_nonceorwindow.pie_pr_backend_dec_vars_array?.ajax_nonce.
- Navigate to the newly created page using
- Verification: Check if the nonce is intended for unauthenticated use (
nopriv). If the action string used inwp_verify_nonceorcheck_ajax_refereris generic (e.g.,piereg_nonceor-1), the extracted nonce will be valid for the exploit.
5. Exploitation Strategy
The goal is to modify the field order of the default registration form.
- Request Method: POST
- URL:
http://[target]/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Payload Body:
(Note: Reversing the order of existing fields 1 and 2 proves unauthorized modification).action=pie_register_update_field_order& form_id=default& field_order[]=2& field_order[]=1& _wpnonce=[EXTRACTED_NONCE]
6. Test Data Setup
- Install Plugin: Ensure Pie Register v3.8.4.9 is installed and activated.
- Default Form: Ensure the default registration form exists (created automatically on install).
- Public Page:
wp post create --post_type=page --post_title="Register" --post_status=publish --post_content="[pie_register_form]" - Baseline State: Record the current field order:
wp option get piereg_form_fields_default
7. Expected Results
- Response: The server returns a success code (e.g.,
1,true, or a JSON success message). - State Change: The database option
piereg_form_fields_defaultis updated to reflect the newfield_orderprovided in the payload.
8. Verification Steps
- DB Check: Use WP-CLI to verify the option value has changed:
wp option get piereg_form_fields_default --format=json - UI Check: Navigate to the registration page and observe if the fields have been reordered or if the form is broken (indicating corruption).
9. Alternative Approaches
- Settings Reset: If
pie_register_update_field_orderis not available, attempt thepie_register_hide_noticesorpie_register_reset_settingsactions, which often share the same lack of authorization. - Malformed form_id: Try setting
form_idto an arbitrary integer to see if the plugin creates newpiereg_form_fields_Xoptions, potentially leading to database bloat or configuration injection.
Summary
The Pie Register plugin for WordPress fails to implement proper authorization checks on its AJAX handlers, allowing unauthenticated users to perform administrative actions. Attackers can exploit this to modify registration form configurations, including reordering or deleting fields, by sending crafted requests to the plugin's AJAX endpoints.
Vulnerable Code
// File: classes/base.php // The getCurrentFields function shows how form configurations are retrieved from options, // but the corresponding update handlers lack current_user_can('manage_options') checks. function getCurrentFields($id="") { if(((int)$id) != 0 and $id != "" ) { $data = get_option("piereg_form_fields_".((int)$id)); } else if(isset($_GET['form_id']) and ((int)$_GET['form_id']) != 0 ){ $data = get_option("piereg_form_fields_".((int)sanitize_key($_GET['form_id']))); } else{ $data = get_option("pie_fields_default"); } $data = maybe_unserialize($data ); --- // File: pie-register.php // Handlers are registered in pieActions() and often lack capability checks // even when registered via wp_ajax_nopriv_ function __construct() { global $pagenow, $wp_version, $profile; ///// $this->is_pr_preview = false; $this->pie_pr_dec_vars_array = false; $this->pie_pr_backend_dec_vars_array = false; $this->pie_ua_renew_account_url = false; $this->pie_is_social_renew_account_call = false; $this->pie_after_login_page_redirect_url = false; /////////////////// $this->pie_payment_methods_dat = apply_filters('add_select_payment_script_', $this->pie_payment_methods_dat); /////////////////// $this->ipn_status = ''; $this->txn_id = null; $this->ipn_log = true; $this->ipn_response = ''; $this->ipn_debug = false; //self::$pieinstance = $this; /***********************/ parent::__construct(); $this->pieActions(); $this->pieFilters(); $errors = new WP_Error();
Security Fix
Only in /home/deploy/wp-safety.org/data/plugin-versions/pie-register/3.8.4.9/assets/css/images: ui-bg_gloss-wave_35_f6a828_500x100(1).png @@ -1718,7 +1718,7 @@ $pending_payment_url = ""; $register_type = get_user_meta($user->ID, 'register_type', true); if($register_type == "payment_verify"){ - $hash = md5( time() ); + $hash = wp_generate_password(32, false); update_user_meta( $user->ID, 'hash', $hash ); $user_registered_form_id = get_user_meta($user->ID, "user_registered_form_id" , true); @@ -3912,7 +3912,7 @@ $piereg = get_option(OPTION_PIE_REGISTER); $date_time = date_i18n("d-m-Y H:i:s"); - $key = md5( time() ); + $key = wp_generate_password(32, false); $data = get_option("piereg_payment_log_option"); $duplicate_enty = false; @@ -162,7 +162,7 @@ /* * Generate Key */ - $email_key = md5((uniqid("piereg_").time())); + $email_key = wp_generate_password(32, false); /* * Email Key add in array for email template */ @@ -559,6 +559,5 @@ require_once( get_stylesheet_directory().'/pie-register/pie_register_template/profile_edit/edit_form_template.php' ); } else{ - require_once(PIEREG_DIR_NAME.'/pie_register_template/profile_edit/edit_form_template.php'); - + require_once(PIEREG_DIR_NAME.'/pie_register_template/profile_edit/edit_form_template.php'); } @@ -4,7 +4,7 @@ Plugin Name: Pie Register - Basic Plugin URI: https://pieregister.com/ Description: Create custom user registration forms, drag & drop form builder, send invitation codes, add conditional logic, 2-step authentication, assign user roles, accept payments and more! -Version: 3.8.4.9 +Version: 3.8.4.10 Author: Pie Register Author URI: https://pieregister.com/ Text Domain: pie-register @@ -2610,7 +2610,7 @@ if ($register_type == "admin_email_verify" && !$this->InvCodeExpired($user_id)) { update_user_meta($user_id, 'active', 0); - $hash = md5(time()); + $hash = wp_generate_password(32, false); update_user_meta($user_id, 'hash', $hash); update_user_meta($user_id, 'register_type', "email_verify"); @@ -3969,7 +3969,7 @@ } else if ($option_user_verification == 1) //Admin Verification { update_user_meta($user_id, 'active', 0); - $admin_hash = md5(time()); + $admin_hash = wp_generate_password(32, false); update_user_meta($user_id, 'admin_hash', $admin_hash); update_user_meta($user_id, 'register_type', "admin_verify"); @@ -4009,7 +4009,7 @@ } else if ($option_user_verification == 2) //E-Mail Link Verification { update_user_meta($user_id, 'active', 0); - $hash = md5(time()); + $hash = wp_generate_password(32, false); update_user_meta($user_id, 'hash', $hash); update_user_meta($user_id, 'register_type', "email_verify"); @@ -4292,7 +4292,7 @@ $option = get_option(OPTION_PIE_REGISTER); update_user_meta($user_id, 'active', 0); - $hash = md5(time()); + $hash = wp_generate_password(32, false); update_user_meta($user_id, 'hash', $hash); $subject = html_entity_decode($option['user_subject_email_pending_payment'], ENT_COMPAT, "UTF-8"); @@ -4453,7 +4453,7 @@ $user_email = $user->user_email; update_user_meta($user_id, 'active', 0); - $hash = md5(time()); + $hash = wp_generate_password(32, false); update_user_meta($user_id, 'hash', $hash); update_user_meta($user_id, 'admin_hash', ""); update_user_meta($user_id, 'register_type', "email_verify"); @@ -4609,7 +4609,7 @@ } $sent++; update_user_meta($user_id, 'active', 0); - $hash = md5(time()); + $hash = wp_generate_password(32, false); update_user_meta($user_id, 'hash', $hash); @@ -4671,7 +4671,7 @@ } $sent++; update_user_meta($user_id, 'active', 0); - $hash = md5(time()); + $hash = wp_generate_password(32, false); update_user_meta($user_id, 'hash', $hash); $user = new WP_User($user_id); @@ -7782,7 +7782,7 @@ if ($email_verify_orignal_key == $email_verify_key) { $new_email_address = get_user_meta($user_data_temp->data->ID, "new_email_address", true); - $email_key = md5(uniqid("piereg_") . time()); + $email_key = wp_generate_password(32, false); $keys_array = array("reset_email_key" => $email_key); /* @@ -5,7 +5,7 @@ Requires at least: 4.0 Tested up to: 6.9 Requires PHP: 5.6 -Stable tag: 3.8.4.9 +Stable tag: 3.8.4.10 License: GPL-2.0-or-later License URI: https://www.gnu.org/licenses/gpl-2.0.html @@ -231,6 +231,12 @@ == CHANGELOG == +### 3.8.4.10 + +*Released Date 14th May 2026* + +* Security: Improved token generation in verification + ### 3.8.4.9 *Released Date 30th March 2026*
Exploit Outline
The exploit target is the unauthenticated AJAX handler for updating registration form configurations. 1. Locate a public page containing the [pie_register_form] shortcode to trigger the enqueueing of scripts and extraction of a valid security nonce (localized in the 'pie_pr_dec_vars_array' JavaScript object). 2. Construct a POST request to '/wp-admin/admin-ajax.php' using the 'pie_register_update_field_order' action. 3. Include a 'form_id' (e.g., 'default') and a 'field_order[]' array containing a new sequence of field IDs to reorder or corrupt the form structure. 4. Since the plugin fails to perform 'current_user_can('manage_options')' checks within the AJAX handler, the request will be processed, and the 'piereg_form_fields_{form_id}' option in the database will be updated without authentication.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.