Kali Forms <= 2.4.9 - Unauthenticated Remote Code Execution via form_process
Description
The Kali Forms plugin for WordPress is vulnerable to Remote Code Execution in all versions up to, and including, 2.4.9 via the 'form_process' function. This is due to the 'prepare_post_data' function mapping user-supplied keys directly into internal placeholder storage, combined with the use of 'call_user_func' on these placeholder values. This makes it possible for unauthenticated attackers to execute code on the server.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:HTechnical Details
What Changed in the Fix
Changes introduced in v2.4.10
Source Code
WordPress.org SVN# Vulnerability Research Plan - CVE-2026-3584 ## 1. Vulnerability Summary The **Kali Forms** plugin (versions <= 2.4.9) contains an unauthenticated Remote Code Execution (RCE) vulnerability within its AJAX form processing logic. The flaw exists because the `Form_Processor` class allows user-supplie…
Show full research plan
Vulnerability Research Plan - CVE-2026-3584
1. Vulnerability Summary
The Kali Forms plugin (versions <= 2.4.9) contains an unauthenticated Remote Code Execution (RCE) vulnerability within its AJAX form processing logic. The flaw exists because the Form_Processor class allows user-supplied data from the kf_hooks parameter to be merged directly into the internal $placeholdered_data array. Subsequently, the plugin's placeholder resolution logic (likely within Emailer or get_thank_you_message) uses call_user_func() on these values. An attacker can overwrite standard placeholder tags with a malicious callback and argument, triggering arbitrary code execution when the plugin attempts to render the form's success message or send notifications.
2. Attack Vector Analysis
- Endpoint:
POST /wp-admin/admin-ajax.php - Action:
kaliforms_form_process(registered for bothwp_ajax_andwp_ajax_nopriv_) - Vulnerable Parameters:
data[kf_hooks][TAG_NAME][callback]data[kf_hooks][TAG_NAME][value]
- Authentication: Unauthenticated.
- Preconditions:
- A valid Kali Form must exist.
- The attacker must obtain a valid nonce for the
kaliforms_form_processaction. - The form's "
Summary
The Kali Forms plugin is vulnerable to unauthenticated Remote Code Execution (RCE) because it allows user-supplied data to overwrite internal placeholder configurations. Attackers can inject malicious PHP callbacks into the plugin's placeholder system via the 'kf_hooks' parameter, which are subsequently executed using call_user_func() during form processing.
Vulnerable Code
// Inc/Frontend/class-form-processor.php // Line 213 in v2.4.9 if (isset($this->data['kf_hooks']) && !empty($this->data['kf_hooks'])) { $this->placeholdered_data = array_merge($this->placeholdered_data, $this->data['kf_hooks']); } --- // Line 239 in v2.4.9 if (isset($this->data['kf_hooks']) && !empty($this->data['kf_hooks'])) { $this->placeholdered_data = array_merge($this->placeholdered_data, $this->data['kf_hooks']); }
Security Fix
@@ -256,11 +256,22 @@ public function check_if_placeholders_changed() { // 1.6.3 fix - the checkbox "string" value was overwritten with the "source of truth" + if ($this->post !== null && empty($this->field_type_map)) { + $prepared_maps = $this->setup_field_map(); + $this->field_type_map = $prepared_maps['map']; + $this->advanced_field_map = $prepared_maps['advanced']; + } + foreach ($this->data as $key => $value) { + if (!array_key_exists($key, $this->field_type_map)) { + continue; + } + $type = 'textbox'; - if (isset($this->field_type_map[$key]) && !empty($this->field_type_map[$key])) { + if (!empty($this->field_type_map[$key])) { $type = $this->field_type_map[$key]; } + $this->_run_placeholder_switch($type, $key, $value); } } @@ -340,8 +351,12 @@ $data = array_merge($data, $this->_get_product_fields($data)); foreach ($data as $k => $v) { + if (!array_key_exists($k, $this->field_type_map)) { + continue; + } + $type = 'textbox'; - if (isset($this->field_type_map[$k]) && !empty($this->field_type_map[$k])) { + if (!empty($this->field_type_map[$k])) { $type = $this->field_type_map[$k]; } @@ -380,10 +395,28 @@ $this->placeholdered_data = apply_filters($this->slug . '_form_placeholders', $this->placeholdered_data); + $this->restore_internal_callable_placeholders(); + return $data; } /** + * Ensure built-in placeholder callbacks cannot be replaced by field names that mirror + * reserved keys or untrusted POST keys (call_user_func targets in _save_data). + * + * @return void + */ + private function restore_internal_callable_placeholders() + { + $defaults = (new GeneralPlaceholders())->general_placeholders; + foreach (['{entryCounter}', '{thisPermalink}', '{submission_link}'] as $key) { + if (isset($defaults[$key])) { + $this->placeholdered_data[$key] = $defaults[$key]; + } + } + } + + /** * Get product total * * @param [type] $data
Exploit Outline
To exploit this vulnerability, an unauthenticated attacker performs the following steps: 1. Identifies a target WordPress site running Kali Forms <= 2.4.9 and finds a page containing a form to extract the form ID and the 'kaliforms_form_process' AJAX nonce. 2. Sends a POST request to /wp-admin/admin-ajax.php with the 'action' parameter set to 'kaliforms_form_process'. 3. Includes a payload in the 'data[kf_hooks]' parameter. This payload should target a known internal placeholder (e.g., '{submission_link}') and provide a nested array containing a 'callback' (the PHP function to execute, like 'system') and a 'value' (the command argument, like 'id'). 4. The plugin's Form_Processor class merges this malicious hook into its internal $placeholdered_data array. 5. When the plugin later attempts to resolve placeholders for the form's success message or email notification, it encounters the attacker-supplied callback and executes it via call_user_func(), resulting in arbitrary command execution on the server.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.