FunnelKit Automations – Email Marketing Automation and CRM for WordPress & WooCommerce <= 3.7.3 - Missing Authorization
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:NTechnical Details
<=3.7.3What Changed in the Fix
Changes introduced in v3.8.0
Source Code
WordPress.org SVN# 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 executingBWFAN_Model_Automationmeta::insert_automation_meta_data.
3. Code Flow
- Entry Point: The
wp_ajax_bwf_migrate_automationhook triggersBWFAN_Admin::bwfan_migrate_automation(). - Nonce Check:
BWFAN_Common::check_nonce()is called. In this plugin, this typically validates the_wpnoncePOST parameter against thebwfan_unique_secretoption. - Data Processing:
- The code retrieves
automation_idfrom$_POST. - It calls
BWFAN_Model_Automationmeta::insert_automation_meta_data( $id, ['v1_migrate' => true] ).
- The code retrieves
- Sink: The
insert_automation_meta_datamethod performs a databaseINSERTorUPDATEinto thewp_bwfan_automationmetatable (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.
- Leaked Via: The
BWFCRM_Base_React_Pageclass (parent of dashboard/automation pages) prepares$this->page_data['bwfan_nonce']usingget_option( 'bwfan_unique_secret', '' ). - 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:
- Login as a Subscriber.
- Navigate to
/wp-admin/profile.php. - Use
browser_evalto 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.
- The plugin enqueues assets on various admin pages. Because the plugin hooks into
5. Exploitation Strategy
- Preparation:
- Create a dummy automation in the database to have a valid
automation_id.
- Create a dummy automation in the database to have a valid
- Execution:
- Use the
http_requesttool to send the POST request from the Subscriber session.
- Use the
- 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] - Verification:
- Check the response JSON for
{"msg":"Automation migrated","status":true}. - Verify the database change using WP-CLI.
- Check the response JSON for
6. Test Data Setup
- Create Subscriber:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password - Create Automation:
Since FunnelKit uses custom tables, usewp evalto insert a record:
(Note: Verify the exact table prefix// Create a dummy automation record global $wpdb; $wpdb->insert($wpdb->prefix . 'bwfan_automations', [ 'title' => 'Test Automation', 'status' => 'active' ]); echo "Automation ID: " . $wpdb->insert_id;bwfan_in the environment).
7. Expected Results
- The AJAX request should return a
200 OKstatus with a JSON body:{ "msg": "Automation migrated", "status": true } - The database table
wp_bwfan_automationmetashould now contain a row for the specifiedautomation_idwithmeta_key = 'v1_migrate'andmeta_value = '1'(serialized asb:1;or simply1).
8. Verification Steps
- Check Database via WP-CLI:
wp db query "SELECT * FROM wp_bwfan_automationmeta WHERE meta_key = 'v1_migrate' AND automation_id = [TARGET_ID];" - 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
nonceparameter instead of_wpnonce. - Metadata Overwrite: Try passing other meta keys in the array if the
insert_automation_meta_datafunction is found to be more flexible than thebwfan_migrate_automationwrapper suggests (though the provided source explicitly hardcodesv1_migrate).
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
@@ -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.