weForms – Easy Drag & Drop Contact Form Builder For WordPress <= 1.6.26 - Unauthenticated PHP Object Injection
Description
The weForms – Easy Drag & Drop Contact Form Builder For WordPress plugin for WordPress is vulnerable to PHP Object Injection in versions up to, and including, 1.6.26 via deserialization of untrusted input. This makes it possible for unauthenticated attackers to inject a PHP Object. No known POP chain is present in the vulnerable software. If a POP chain is present via an additional plugin or theme installed on the target system, it could allow the attacker to delete arbitrary files, retrieve sensitive data, or execute code.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:HTechnical Details
What Changed in the Fix
Changes introduced in v1.6.27
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-32484 (weForms Object Injection) ## 1. Vulnerability Summary The **weForms** plugin (<= 1.6.26) is vulnerable to **Unauthenticated PHP Object Injection**. The vulnerability exists because the plugin's entry-handling logic retrieves submitted form data from th…
Show full research plan
Exploitation Research Plan - CVE-2026-32484 (weForms Object Injection)
1. Vulnerability Summary
The weForms plugin (<= 1.6.26) is vulnerable to Unauthenticated PHP Object Injection. The vulnerability exists because the plugin's entry-handling logic retrieves submitted form data from the database and passes it directly to unserialize() or maybe_unserialize() when instantiating a WeForms_Form_Entry object. Since an unauthenticated user can submit form entries, they can inject a serialized PHP object payload into a field that the plugin later deserializes.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
weforms_frontend_submit(registered viawp_ajax_nopriv_weforms_frontend_submitinincludes/class-ajax.php) - Vulnerable Parameter: Within the
form_dataPOST parameter, any field name corresponding to amultiple_productorimage_uploadfield type. - Authentication: None required (Unauthenticated).
- Preconditions: A published form must exist containing at least one field of type
multiple_product,image_upload, orfile_upload.
3. Code Flow
- Entry Point:
WeForms_Ajax::handle_frontend_submission()is called via AJAX. - Processing: The function parses `$_
Summary
The weForms plugin is vulnerable to Unauthenticated PHP Object Injection because it uses unserialize() and maybe_unserialize() on user-controllable form entry data stored in the database. An attacker can submit a malicious serialized PHP object through specific form fields, which is later deserialized when an administrator views the entry or when the system processes the entry data.
Vulnerable Code
// includes/class-form-entry.php } elseif ( in_array( $field['type'], [ 'image_upload', 'file_upload' ] ) ) { $file_field = ''; $value = maybe_unserialize( $value ); --- // includes/class-form-entry.php line 199 } elseif ( $field['type'] == 'multiple_product' ) { $field_value = unserialize( $value ); --- // includes/class-ajax.php line 523 $payment = $entry->get_payment_data(); if ( isset( $payment->payment_data ) && is_serialized( $payment->payment_data ) ) { $payment->payment_data = unserialize( $payment->payment_data ); } --- // includes/functions.php line 1251 function weforms_get_pain_text( $value ) { if ( is_serialized( $value ) ) { $value = unserialize( $value ); }
Security Fix
@@ -218,7 +218,10 @@ } public static function process_payment_data( $payment_data ) { - $field_value = unserialize( $payment_data->payment_data ); + // Security fix: Prevent PHP Object Injection by restricting allowed classes + $field_value = is_serialized( $payment_data->payment_data ) + ? @unserialize( $payment_data->payment_data, [ 'allowed_classes' => false ] ) + : $payment_data->payment_data; $serialized_value = []; $transaction_data = []; @@ -1548,7 +1548,8 @@ $payment = $entry->get_payment_data(); if ( isset( $payment->payment_data ) && is_serialized( $payment->payment_data ) ) { - $payment->payment_data = unserialize( $payment->payment_data ); + // Security fix: Prevent PHP Object Injection by restricting allowed classes + $payment->payment_data = @unserialize( $payment->payment_data, [ 'allowed_classes' => false ] ); } $has_empty = false; @@ -520,7 +520,8 @@ $payment = $entry->get_payment_data(); if ( isset( $payment->payment_data ) && is_serialized( $payment->payment_data ) ) { - $payment->payment_data = unserialize( $payment->payment_data ); + // Security fix: Prevent PHP Object Injection by restricting allowed classes + $payment->payment_data = @unserialize( $payment->payment_data, [ 'allowed_classes' => false ] ); } if ( false === $fields ) { @@ -170,7 +170,10 @@ } } elseif ( in_array( $field['type'], [ 'image_upload', 'file_upload' ] ) ) { $file_field = ''; - $value = maybe_unserialize( $value ); + // Security fix: Prevent PHP Object Injection by restricting allowed classes + $value = is_serialized( $value ) + ? @unserialize( $value, [ 'allowed_classes' => false ] ) + : $value; if ( is_array( $value ) && $value ) { foreach ( $value as $attachment_id ) { @@ -196,7 +199,10 @@ 'long' => trim( $long ), ]; } elseif ( $field['type'] == 'multiple_product' ) { - $field_value = unserialize( $value ); + // Security fix: Prevent PHP Object Injection by restricting allowed classes + $field_value = is_serialized( $value ) + ? @unserialize( $value, [ 'allowed_classes' => false ] ) + : $value; $serialized_value = []; @@ -218,7 +224,10 @@ $value = implode( '<br> <br> ', $serialized_value ); } } elseif ( $field['type'] == 'checkbox_grid' ) { - $entry_value = unserialize( $value ); + // Security fix: Prevent PHP Object Injection by restricting allowed classes + $entry_value = is_serialized( $value ) + ? @unserialize( $value, [ 'allowed_classes' => false ] ) + : $value; if ( $entry_value ) { $return = ''; @@ -281,7 +290,10 @@ $value = $return; } } elseif ( $field['type'] == 'multiple_choice_grid' ) { - $entry_value = unserialize( $value ); + // Security fix: Prevent PHP Object Injection by restricting allowed classes + $entry_value = is_serialized( $value ) + ? @unserialize( $value, [ 'allowed_classes' => false ] ) + : $value; if ( $entry_value ) { $return = ''; @@ -344,7 +356,10 @@ $value = $return; } } elseif ( $field['type'] == 'address_field' || is_serialized( $value ) ) { - $field_value = unserialize( $value ); + // Security fix: Prevent PHP Object Injection by restricting allowed classes + $field_value = is_serialized( $value ) + ? @unserialize( $value, [ 'allowed_classes' => false ] ) + : $value; $serialized_value = []; @@ -1248,14 +1248,15 @@ * @return string **/ function weforms_get_pain_text( $value ) { - if ( is_serialized( $value ) ) { - $value = unserialize( $value ); - } + // Security fix: Removed unsafe unserialize() call to prevent PHP Object Injection. + // WordPress's get_metadata() already handles deserialization safely. + // Any serialized strings at this point should be treated as untrusted user input. if ( is_array( $value ) ) { $string_value = []; foreach ( $value as $key => $single_value ) { - if ( is_array( $single_value ) || is_serialized( $single_value ) ) { + // Only recursively process arrays, not serialized strings + if ( is_array( $single_value ) ) { $single_value = weforms_get_pain_text( $single_value ); }
Exploit Outline
1. Identify a published weForms form that contains at least one complex field type that results in database serialization (e.g., File Upload, Multiple Products, Checkbox Grid, or Address field). 2. Construct a malicious serialized PHP object payload designed to trigger a POP chain (if one exists in the environment's themes or other plugins). 3. Submit the form as an unauthenticated user by sending a POST request to `wp-admin/admin-ajax.php` with the action `weforms_frontend_submit`. 4. In the `form_data` payload, map the malicious serialized string to the field name corresponding to the vulnerable field type. 5. Wait for an administrator to view the form entries or trigger a system process (like an export or privacy data request) that forces the backend to instantiate a `WeForms_Form_Entry` object, which will trigger the unsafe `unserialize()` call.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.