CVE-2026-3584

Kali Forms <= 2.4.9 - Unauthenticated Remote Code Execution via form_process

criticalImproper Control of Generation of Code ('Code Injection')
9.8
CVSS Score
9.8
CVSS Score
critical
Severity
2.4.10
Patched in
1d
Time to patch

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:H
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
High
Confidentiality
High
Integrity
High
Availability

Technical Details

Affected versions<=2.4.9
PublishedMarch 20, 2026
Last updatedMarch 20, 2026
Affected pluginkali-forms

What Changed in the Fix

Changes introduced in v2.4.10

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Verified by PoC

# 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 both wp_ajax_ and wp_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_process action.
    • The form's "
Research Findings

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

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/kali-forms/2.4.9/Inc/Frontend/class-form-processor.php /home/deploy/wp-safety.org/data/plugin-versions/kali-forms/2.4.10/Inc/Frontend/class-form-processor.php
--- /home/deploy/wp-safety.org/data/plugin-versions/kali-forms/2.4.9/Inc/Frontend/class-form-processor.php	2026-01-08 10:05:42.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/kali-forms/2.4.10/Inc/Frontend/class-form-processor.php	2026-03-20 08:23:24.000000000 +0000
@@ -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.