Privilege escalation vulnerability in WordPress ND Shortcodes For Visual Composer plugin.

The WordPress ND Shortcodes For Visual Composer plugin, which has 10,000+ active installations, was prone to a critical vulnerability that would allow an unauthenticated user to modify the settings of WordPress and to take over the blog and its database.

This vulnerability is currently being exploited, make sure to follow the recommendations below

Unauthenticated options change

In version <=5.8, the plugin registers the nd_options_import_settings_php_function action via both the wp_ajax_* and wp_ajax_nopriv_* hooks in the ‘nd-shortcodes/inc/settings/import-export/index.php’ script:

add_action( 'wp_ajax_nd_options_import_settings_php_function', 'nd_options_import_settings_php_function' );
add_action( 'wp_ajax_nopriv_nd_options_import_settings_php_function', 'nd_options_import_settings_php_function' );

The wp_ajax_* hook allows logged-in users to access WordPress AJAX functions while the wp_ajax_nopriv_* hooks allows unauthenticated users to perform the same action. In ND Shortcodes, the AJAX request is sent to the ‘nd_options_import_settings_php_function’ function used to import the plugin settings:

function nd_options_import_settings_php_function() {

  //recover datas
  $nd_options_value_import_settings = $_GET['nd_options_value_import_settings'];

  $nd_options_import_settings_result = '';

  if ( $nd_options_value_import_settings != '' ) {

    $nd_options_array_options = explode("[nd_options_end_option]", $nd_options_value_import_settings);

    foreach ($nd_options_array_options as $nd_options_array_option) {
      $nd_options_array_single_option = explode("[nd_options_option_value]", $nd_options_array_option);
      $nd_options_option = $nd_options_array_single_option[0];
      $nd_options_new_value = $nd_options_array_single_option[1];
      $nd_options_new_value = str_replace("[SHARP]","#",$nd_options_new_value);

      if ( $nd_options_new_value != '' ){

        //remove \ from new value
        $nd_options_new_value_str_replace = str_replace("\'", "'", $nd_options_new_value );

        $nd_options_update_result = update_option($nd_options_option,$nd_options_new_value_str_replace);


It retrieves the $_GET['nd_options_value_import_settings'] payload and assign it to the $nd_options_value_import_settings variable. Its content is parsed and passed on to the ‘update_option’ function that is used to update WordPress settings in the database (wp_options table). Because there’s no capability check and the function is accessible to anyone, an unauthenticated user can change the blog settings, for instance the site URL, the admin email address, user roles and capabilities, or give administrator privilege to any new registered user. This is a critical vulnerability similar to the Easy WP SMTP plugin zero-day vulnerability that we mentioned a few weeks ago.
There’s no security nonce to protect against CSRF attacks either. Additionally, the $nd_options_option value is not checked to make sure that only the expected options are updated, which could even lead the administrator to mistakenly corrupt the blog settings.

Note that the vulnerability requires that the blog uses one of the several themes from the author in order to exploit it, otherwise the settings page isn’t loaded:

//include settings
if ( get_option('nicdark_theme_author') == 1 ){
  require_once dirname( __FILE__ ) . '/inc/settings/index.php'; 


The vulnerability was discovered and reported to the team on July 24, 2019.


Update as soon as possible if you have are using version 5.8 or below.
If you are using our web application firewall for WordPress, NinjaFirewall WP Edition (free) and NinjaFirewall WP+ Edition (premium), you are protected against this type of vulnerability.

Stay informed about the latest vulnerabilities in WordPress plugins and themes: @nintechnet