WP Insightly for Contact Form 7, WPForms, Elementor, Formidable and Ninja Forms <= 1.1.5 - Missing Authorization
Description
The WP Insightly for Contact Form 7, WPForms, Elementor, Formidable and Ninja Forms plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 1.1.5. 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
<=1.1.5What Changed in the Fix
Changes introduced in v1.1.6
Source Code
WordPress.org SVNThis research plan focuses on exploiting a **Missing Authorization** vulnerability in the **WP Insightly** plugin (version <= 1.1.5). The vulnerability allows authenticated users with Subscriber-level permissions to perform administrative actions, such as modifying plugin feeds or triggering CRM syn…
Show full research plan
This research plan focuses on exploiting a Missing Authorization vulnerability in the WP Insightly plugin (version <= 1.1.5). The vulnerability allows authenticated users with Subscriber-level permissions to perform administrative actions, such as modifying plugin feeds or triggering CRM synchronization, because the AJAX handlers fail to verify user capabilities.
1. Vulnerability Summary
- Vulnerability: Missing Authorization (Insecure Direct Object Reference / Missing Capability Check).
- Location:
includes/plugin-pages.phpwithin thevxcf_insightly_pagesclass. - Problem: The plugin registers multiple AJAX actions via
wp_ajax_hooks. While these hooks correctly restrict access to authenticated users, the callback functions (e.g.,update_feed,send_to_crm,refresh_data) do not perform acurrent_user_can('manage_options')check. - Impact: A Subscriber can modify plugin configuration (Integrity) or trigger unauthorized data transmissions to Insightly CRM.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
update_feed_vxcf_insightly(inferred from$this->id = "vxcf_insightly"incf7-insightly.php). - Authentication: Authenticated (Subscriber level or higher).
- Payload: URL-encoded POST parameters including a nonce and feed configuration.
- Preconditions:
- The plugin must be active.
- At least one "Feed" must exist in the plugin (to modify).
- The attacker must obtain a valid WordPress nonce (
vx_nonce).
3. Code Flow
- Registration: In
includes/plugin-pages.php, the__constructmethod registers AJAX handlers using the patternwp_ajax_update_feed_vxcf_insightly. - Trigger: A Subscriber sends a POST request to
admin-ajax.phpwithaction=update_feed_vxcf_insightly. - Execution: WordPress routes the request to
vxcf_insightly_pages::update_feed. - Failure: The handler likely calls
check_ajax_referer('vx_nonce', 'nonce')but fails to callcurrent_user_can('manage_options'). The code proceeds to update the database tablewp_vxcf_insightly_feedsbased on$_POSTdata.
4. Nonce Acquisition Strategy
The nonce is generated using wp_create_nonce('vx_nonce'). In CRM Perks plugins, this nonce is typically exposed in the admin dashboard.
Strategy:
- The plugin often registers its submenus with the
readcapability (allowing Subscribers to see them) or leaks the nonce in the global admin script data. - Access Test: Navigate to the plugin's main page as a Subscriber:
/wp-admin/admin.php?page=vxcf_insightly. - Extraction:
- If the page loads, use
browser_evalto extract the nonce from the hidden input field:document.getElementById('vx_nonce_field')?.value - Alternatively, check the global JS object (localized via
wp_localize_script):window.vxcf_insightly_pages?.nonce(or similar, based on the$this->id).
- If the page loads, use
5. Exploitation Strategy
We will demonstrate the vulnerability by modifying an existing feed's name using a Subscriber account.
Step 1: Obtain Nonce
Use the browser_navigate and browser_eval tools to grab the vx_nonce.
Step 2: Submit Malicious Update
Perform a POST request to admin-ajax.php.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
(Note: Parameters based on standard CRM Perks feed update logic. Ifaction=update_feed_vxcf_insightly&nonce=[NONCE]&feed_id=1&feed_name=VULNERABILITY_CONFIRMED&active=1update_feedexpects a serialized object, thefeedparameter may be used instead.)
6. Test Data Setup
- Admin Action: Log in as Admin.
- Plugin Setup:
- Go to "Insightly Feeds" and create one dummy feed named "Original Feed".
- Note the
idof the feed (usually1for the first feed).
- Subscriber Setup: Create a user
attackerwith thesubscriberrole.
7. Expected Results
- The AJAX request should return a success message (likely JSON or a string like
1orupdated). - The Subscriber's request is accepted despite lacking administrative privileges.
- The database record for the feed will be updated.
8. Verification Steps
- Database Check: Use WP-CLI to verify the feed name changed:
wp db query "SELECT name FROM wp_vxcf_insightly_feeds WHERE id=1" - UI Check: Log back in as Admin and view the Feeds list to see the altered name "VULNERABILITY_CONFIRMED".
9. Alternative Approaches
If update_feed is strictly protected, target refresh_data_vxcf_insightly:
- Action:
refresh_data_vxcf_insightly - Payload:
action=refresh_data_vxcf_insightly&nonce=[NONCE] - Effect: Triggers an unauthorized API refresh/sync with Insightly.
If the Subscriber cannot access the plugin admin pages directly to get a nonce:
- Check if the plugin enqueues its scripts on the Dashboard (
index.php). - Try to find the nonce in the source of
wp-admin/index.php. - If
check_ajax_refereris used withdie=false(common in some CRM Perks versions), try omitting the nonce entirely.
Summary
The WP Insightly plugin for WordPress fails to implement capability checks on several AJAX handlers, most notably the log detail viewer. This allows authenticated attackers, such as Subscribers, to access sensitive CRM logs, modify plugin settings, or trigger unauthorized data synchronization with the Insightly CRM.
Vulnerable Code
// includes/plugin-pages.php lines 19-30 public function __construct() { $this->data=$this->get_data_object(); global $pagenow; if(in_array($pagenow, array("admin-ajax.php"))){ add_action('wp_ajax_update_feed_'.$this->id, array($this, 'update_feed')); add_action('wp_ajax_update_feed_sort_'.$this->id, array($this, 'update_feed_sort')); add_action('wp_ajax_get_field_map_'.$this->id, array($this, 'get_field_map_ajax')); add_action('wp_ajax_get_field_map_object_'.$this->id, array($this, 'get_field_map_object_ajax')); add_action('wp_ajax_get_objects_'.$this->id, array($this, 'get_objects_ajax')); add_action('wp_ajax_log_detail_'.$this->id, array($this, 'log_detail')); add_action('wp_ajax_refresh_data_'.$this->id, array($this, 'refresh_data')); add_action('wp_ajax_send_to_crm_'.$this->id, array($this, 'send_to_crm')); } --- // includes/plugin-pages.php line 1416 (v1.1.5) public function log_detail(){ $log_id=$this->post('id'); $log=$this->data->get_log_by_id($log_id); $data=json_decode($log['data'],true);
Security Fix
@@ -2,7 +2,7 @@ /** * Plugin Name: WP Contact Form Insightly * Description: Integrates Contact Form 7, Ninja Forms, <a href="https://wordpress.org/plugins/contact-form-entries/">Contact Form Entries Plugin</a> and many other forms with Insightly allowing form submissions to be automatically sent to your Insightly account -* Version: 1.1.5 +* Version: 1.1.6 * Requires at least: 3.8 * Author URI: https://www.crmperks.com * Plugin URI: https://www.crmperks.com/plugins/contact-form-plugins/contact-form-insightly-plugin/ @@ -24,7 +24,7 @@ public $crm_name = "insightly"; public $id = "vxcf_insightly"; public $domain = "vxcf-insightly"; - public $version = "1.1.5"; + public $version = "1.1.6"; public $update_id = "6000001"; public $min_cf_version = "1.0"; public $type = "vxcf_insightly"; @@ -118,18 +118,7 @@ add_action('init', array($this,'init')); //loading translations load_plugin_textdomain('contact-form-insightly-crm', FALSE, $this->plugin_dir_name(). '/languages/' ); - - self::$db_version=get_option($this->type."_version"); - if(self::$db_version != $this->version && current_user_can( 'manage_options' )){ - $data=$this->get_data_object(); - $data->update_table(); - update_option($this->type."_version", $this->version); - //add post permissions - require_once(self::$path . "includes/install.php"); - $install=new vxcf_insightly_install(); - $install->create_roles(); - - } +$this->maybe_install(true); } } @@ -149,6 +138,27 @@ self::$plugin->instance(); } } } +public function maybe_install($version_check=false){ + + if(current_user_can( 'manage_options' )){ + self::$db_version=get_option($this->type."_version"); + $do_install=false; + if($version_check == false){ + $do_install=true; + }else if(self::$db_version != $this->version){ + $do_install=true; + } + if($do_install){ + $data=$this->get_data_object(); + $data->update_table(); + update_option($this->type."_version", $this->version); + //add post permissions + require_once(self::$path . "includes/install.php"); + $install=new vxcf_insightly_install(); + $install->create_roles(); + } + } +} public function form_submitted($form){ @@ -508,29 +518,6 @@ echo wp_kses_post($message) ; echo '</p></div>'; } - - - /** - * create tables and roles - * - */ - public function install(){ - - if(current_user_can( 'manage_options' )){ - self::$db_version=get_option($this->type."_version"); - if(self::$db_version != $this->version){ - $data=$this->get_data_object(); - $data->update_table(); - update_option($this->type."_version", $this->version); - //add post permissions - require_once(self::$path . "includes/install.php"); - $install=new vxcf_insightly_install(); - $install->create_roles(); - - } - - } - } /** * Contact Form status * @@ -1275,6 +1262,7 @@ */ public function activate(){ $this->plugin_api(true); +$this->maybe_install(); do_action('plugin_status_'.$this->type,'activate'); } /** @@ -1414,6 +1414,11 @@ * */ public function log_detail(){ + check_ajax_referer('vx_crm_ajax','vx_crm_ajax'); + if(!current_user_can($this->id.'_read_logs')){ + esc_html_e('You do not have permissions to access this page','cf7-insightly'); + return; + } $log_id=$this->post('id'); $log=$this->data->get_log_by_id($log_id); $data=json_decode($log['data'],true);
Exploit Outline
The exploit targets administrative AJAX actions that lack permission checks. An authenticated attacker with Subscriber-level access first obtains a valid WordPress nonce (often leaked in script data or accessible via hidden input fields in the plugin's dashboard pages if they are visible). The attacker then sends a POST request to `/wp-admin/admin-ajax.php`. By setting the 'action' parameter to a vulnerable callback like `log_detail_vxcf_insightly` or `update_feed_vxcf_insightly`, the attacker can retrieve sensitive log data or modify CRM integration settings, as the backend handler fails to verify if the user possesses administrative capabilities before executing the request logic.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.