MySQL Databases interface to show MySQL as offline, Updating MariaDB to v10.2.35 or v10.3.26


Upgrading MariaDB to v10.2.35 or v10.3.26 causes the cPanel UI to not read the grants properly, which leads to cause select sites to be inaccessible and the MySQL Database page within the cPanel interface returns the following error.

More important to note that MariaDB should still be running, the cPanel error log should populate the string the UI is having issues reading:

[2020-11-05 07:37:27 +0000] warn [cpmysql] Error (Invalid grant string: SET DEFAULT ROLE 0 FOR '$user'@'$host'
) while parsing grant: SET DEFAULT ROLE 0 FOR '$user'@'$host' at /usr/local/cpanel/Cpanel/ line 956, <STDIN> line 1.
        Cpanel::Mysql::__ANON__(__CPANEL_HIDDEN__...) called at /usr/local/cpanel/3rdparty/perl/530/lib/perl5/cpanel_lib/Try/ line 118

cPanel has opened an internal case for their development team to investigate this further.

For reference, the case number is CPANEL-34745.

Follow this article to receive an email notification when a solution is published in the product. 

Before proceeding with these changes, we encourage you to backup your database in the event a restore is required.

To backup the MySQL database directory, the following command can be executed as root:

mysqldump mysql > /backup/mysql.sql

Once backup is complete, you can proceed with altering that database column order.

The following command performs the appropriate alterations for the database:

mysql -e "ALTER TABLE mysql.user MODIFY IF EXISTS password_last_changed timestamp DEFAULT CURRENT_TIMESTAMP NULL AFTER max_statement_time, MODIFY IF EXISTS password_lifetime smallint unsigned DEFAULT NULL AFTER password_last_changed, MODIFY IF EXISTS account_locked enum('N', 'Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL after password_lifetime;"

Apply the change by restarting the MariaDB service:


They should go into effect immediately. 

yum versionlock clear

Then run upcp to have the MariaDB packages updated:



What is an inode.

An inode is a data structure used to represent a filesystem object, which can be one of various things including a file or a directory. Each file has a single inode, even though they can have different names.

In other words, the number of inodes equals the total number of files and directories on your hosting plan. To ensure optimal performances, we limit the number of inodes upto 250 000 on most of the hosting plan.

Where can I see how many inodes I use.

To check how many inodes are used, log in to your cPanel. In the left sidebar, click on the Statistics icon. Under Disk Space, you will find Files Usage. This equals to your inode usage.

Steps to reduce inode usage.

There are several ways to reduce inode usage.

Delete useless files, old backups and websites

In your cPanel with the File Manager or through a FTP client, you can easily sort and delete files and directories that are not necessary. These can be scripts not in use, old development websites, unused image files…

Remove cache files

Some applications (such as Joomla, Drupal or WordPress for instance) generate a number of cache files used to improve performances. Verifying how big these cache files are and deleting them once in a while is a good practice. You should be able to remove cache files easily directly in the app.

Archive old emails

Every email on your hosting plan adds up to the total number of inodes. It is a good practice to archive older emails or to transfer them to your computer to limit their size on the server.

Also, it is necessary to check the catchall email address that can accumulates thousands of emails and therefore inodes.

Verify where error messages from scripts and CRON tasks go

If your CRON tasks generate error messages, they can be stored (and take a lot of room) on your server. It is important to check where the error messages go in order to reduce inode usage

A List of SMTP and IMAP Server

Default Ports:Server:Authentication:Port:
SMTP Server (Outgoing Messages)Non-EncryptedAUTH25 (or 587)
 Secure (TLS)StartTLS587
 Secure (SSL)SSL465
IMAP Server (Incoming Messages)Non-EncryptedAUTH143
 Secure (TLS)StartTLS143
 Secure (SSL)SSL993

Googlemail – GmailServer:Authentication:Port:
SMTP Server (Outgoing Messages)
IMAP Server (Incoming Messages)

Please make sure, that IMAP access is enabled in the account settings.
Login to your account and enable IMAP.
You also need to enable “less secure apps” (third party apps) in the Gmail settings:
See also: How to enable IMAP/POP3/SMTP for Gmail account

SMTP Server (Outgoing Messages)smtp-mail.outlook.comStartTLS587
IMAP Server (Incoming Messages)imap-mail.outlook.comSSL993
SMTP Server (Outgoing Messages)smtp.office365.comStartTLS587
IMAP Server (Incoming Messages)outlook.office365.comSSL993
 Note: If the above settings are not working for your account, then login into the outlook web app, go to the “Settings” > “Options” > “Account” > “My Account” > “Settings for POP and IMAP Access”.
Yahoo MailServer:Authentication:Port:
SMTP Server (Outgoing Messages)
IMAP Server (Incoming Messages)
Yahoo Mail PlusServer:Authentication:Port:
SMTP Server (Outgoing Messages)
IMAP Server (Incoming Messages)
Yahoo Mail UKServer:Authentication:Port:
SMTP Server (Outgoing Messages)
IMAP Server (Incoming Messages)
Yahoo Mail DeutschlandServer:Authentication:Port:
SMTP Server (Outgoing Messages)
IMAP Server (Incoming Messages)
Yahoo Mail AU/NZServer:Authentication:Port:
SMTP Server (Outgoing Messages)
IMAP Server (Incoming Messages)
SMTP Server (Outgoing Messages)
IMAP Server (Incoming Messages)
SMTP Server (Outgoing Messages)
IMAP Server (Incoming Messages)
NTL @ntlworld.comServer:Authentication:Port:
SMTP Server (Outgoing Messages)smtp.ntlworld.comSSL465
IMAP Server (Incoming Messages)imap.ntlworld.comSSL993
BT ConnectServer:Authentication:Port:
SMTP Server (Outgoing Messages) 25
IMAP Server (Incoming Messages) 143
O2 DeutschlandServer:Authentication:Port:
SMTP Server (Outgoing Messages) 25
IMAP Server (Incoming Messages) 143
T-Online DeutschlandServer:Authentication:Port:
SMTP Server (Outgoing Messages)securesmtp.t-online.deStartTLS587
IMAP Server (Incoming Messages)secureimap.t-online.deSSL993
1&1 (1and1)Server:Authentication:Port:
SMTP Server (Outgoing Messages)smtp.1and1.comStartTLS587
IMAP Server (Incoming Messages)imap.1and1.comSSL993
1&1 DeutschlandServer:Authentication:Port:
SMTP Server (Outgoing Messages)smtp.1und1.deStartTLS587
IMAP Server (Incoming Messages)imap.1und1.deSSL993
SMTP Server (Outgoing Messages) 587
IMAP Server (Incoming Messages) 143
zoho MailServer:Authentication:Port:
SMTP Server (Outgoing Messages)smtp.zoho.comSSL465
IMAP Server (Incoming Messages)imap.zoho.comSSL993
SMTP Server (Outgoing Messages)smtp.mail.comStartTLS587
IMAP Server (Incoming Messages)imap.mail.comSSL993
SMTP Server (Outgoing Messages)
IMAP Server (Incoming Messages)
Net@ddress by USA.NETServer:Authentication:Port:
SMTP Server (Outgoing Messages)smtp.postoffice.netSSL465
IMAP Server (Incoming Messages)imap.postoffice.netSSL993
+ Add ProviderServer:Authentication:Port:
SMTP Server (Outgoing Messages)Contact us to add your provider  
IMAP Server (Incoming Messages)  

How to Check if Railgun is Running on Website

When a request is handled by Railgun, Cloudflare inserts a header with diagnostic information to track how the protocol is doing. If you want to see these headers, you’ll need to use a browser that supports examining header information.

View Railgun header in browser

Google Chrome: View > Developer > Developer Tools menu. You can also install Cloudflare’s Claire extension.

Safari: Develop > Show Web Inspector menu

Firefox: Install Firebug

Microsoft Internet Explorer: You can use a tool like Fiddler

When you are looking for the header information, you should be seeing Cloudflare headers like the following in the response:

cf-railgun:   e95b1c46e0 0.02 0.037872 0030 9878

cf-ray:   478149ad1570291

The CF-Railgun header has up to five codes separated by a space. In order, these codes and their corresponding values from the example of cf-railgun: e95b1c46e0 0.02 0.037872 0030 9878 listed above are:

  • Railgun Request ID: e95b1c46e0 (internal process number that allows us to track what connection handled a request )
  • Compression Ratio: 0.02 (the size of the response after Railgun’s delta compression expressed as a percentage)
  • Origin Processing Time: 0.037872 (that Railgun waits for the origin web server to generate the page)
  • Railgun Flags: 0030 (how a request was processed)
  • Version Number: 9878 (indicates the version of the Railgun Listener software on the origin server’s network)

Fix CPU Overload / Abuse Issues ?

Most common things you need to follow will be:

1. Adding cloudflare for your domains which will protect your domains from Unwanted Traffic/Attack/Bot Access 

2. Add robots.txt to understand Search engines to crawl your sites.There are lot of Crawl bots which will give unwanted traffic to your websites which will also cause Overloading on servers like (EP hits)

So create an robots.txt file under your public_html and place the below code : 

User-Agent: *
Disallow: /User-Agent: Googlebot
Allow: /

If you want to add any other search engines to crawl your site you can add it in the above code 

Follow the Above steps for all your domains which is an recommended thing !

For WordPress Users kindly change the File permission of 2 files under your WordPress root wp-cron.php and xmlrpc.php to Permission 000

You can change it from your cPanel > Filemanager As these 2 files will cause overloading on servers by giving unwanted traffic 

Add Heart Beat Plugin to control the admin-ajax.php Once installed WP Admin > Settings > Heartbeat Control > Disable the heartbeat for All 3 Options and click save

Add loginizer which will protect your sites from WP Login attacks (These attacks on most common your websites will be facing daily) So its best way to change your  WP Admin portal URL (VERY RECOMMENDED)

Keep your WP Core,Plugins,Themes Up to date

Remove any Un-used themes or plugins

Don’t use Jetpack Plugin as it will Eat the Resource

Setup WordPress Security Plugin Wordfence

How to Install and setup the Wordfence Security plugin in WordPress.

First thing you need to do is install and activate the Wordfence Security plugin. For more details, see our step by step guide on how to install a WordPress plugin.

Wordfence Setup – WebhostUK

Setting up the Wordfence Security plugin is very simple, but there are a few areas you really wanna make sure are running, like the Firewall.

Click on Wordfence on the left-hand admin panel and select the Dashboard option. This will pull up the main settings page of the plugin. All of the information you need to see is on this page including the last scan, malware blocked, IP addresses blocked, etc.

Wordfence Setup – WebhostUK

The most important part of this security plugin is the Firewall. It will prevent most malicious activity on your website. This is a PHP based application level firewall.

The Wordfence firewall offers two levels of protection. The basic level which is enabled by default allows the Wordfence firewall to run as a WordPress plugin.

This means, that the firewall will load with rest of your WordPress plugins. This can protect you from several threats, but it will miss out on threats that are designed to trigger before WordPress themes and plugins are loaded.

The second level of protection is called extended protection. It allows Wordfence to run before WordPress core, plugins, and themes. This offers a much better protection against more advanced security threats. Click on the Firewall option to access its settings page.

Wordfence Setup – WebhostUK

Click on the Optimize the Wordfence Firewall button. It will run a test to determine the best setting to use. You may pick your own setting, but I would recommend following Wordfence’s recommendation.

Wordfence Setup – WebhostUK

You may pick your own setting, but I would recommend following Wordfence’s recommendation. Click on the Continue button once you have made your selection.

Click on the Download .htaccess button. This will allow Wordfence to run before your core WordPress files. This adds an extra layer of protection because a firewall cannot protect these files making them vulnerable to hackers. Click on the Continue button once you have the file downloaded.

Wordfence Setup – WebhostUK

You will also notice a Learning Mode button. When you first install Wordfence, it attempts to learn how you and your users interact with the website to make sure that it doesn’t block legitimate visitors. After a week it will automatically switch to Enabled and Protecting mode.

Wordfence Setup – WebhostUK

To scan your website at any time, click on the Scan option.

Wordfence Setup – WebhostUK

Click on the Start a Wordfence Scan button. The free version comes with a default automatic 24-hour scan. If you upgrade to the premium version you can set your own schedule and much more. Once the scan is complete you will see a full list of problems it has found.

Wordfence Setup – WebhostUK

The scan will look for changes in file sizes in the official WordPress core and plugin files.

It will also look inside the files to check for suspicious code, backdoors, malicious URLs, and known patterns of infections.

Typically these scans need a lot of server resources to run. Wordfence does an excellent job of running the scans as efficiently as possible. The time it takes to complete a scan will depend on how much data you have, and the server resources available.

You will be able to see the progress of the scan in the yellow boxes on the scan page. Most of this information will be technical. However, you don’t need to worry about the technical stuff.

Once the scan is finished, Wordfence will show you the results.

It will notify you if it found any suspicious code, infections, malware, or corrupted files on your website. It will also recommend actions you can take to fix those issues.

There are many other sections to be aware of. You can view the live traffic feed by clicking on the Live Traffic option. Wordfence Live Traffic shows you what is happening on your site in real-time, including user logins, hack attempts, and requests that were blocked by the Wordfence Firewall. You can choose to log security-related traffic only or all traffic.

Traffic is logged directly on the server, which means it includes visits that don’t execute JavaScript. Google and other JavaScript-based analytics packages typically only show visits from browsers that are operated by a human, while Live Traffic can show visits from crawlers like Google and Bing.

Here you can see the list of IPs requesting different pages on your website.

Wordfence Setup – WebhostUK

This will show you how well Wordfence is defending your website. The Blocking option will allow you to see who is being blocked and allow you to manually enter an IP address to be blocked.

If you have the premium version you can also block entire countries from accessing your website. Explore these sections to see everything they offer.

Wordfence Setup – WebhostUK

Click on the Options option. This will allow you to tweak the Advanced settings that can be found by scrolling down the page.

These settings are all up to you, but should all be considered when setting this plugin up.

Wordfence Setup – WebhostUK

Congratulations, you have successfully installed and set up the Wordfence Security plugin. You can change your settings and scan your website at any time. Remember there are many features that are exclusive to the premium version of Wordfence and you can upgrade at any time, but the free version will be able to guard your website without any issues.

Install Wordfence Plugin

Installing Wordfence is Both Quick and Simple

With little more than the click of a few buttons, you will have Wordfence up, running and proactively securing your WP site. Once Wordfence is active, it will begin your first security scan and cleanup. You will be able to quash any current threats and begin to prevent future site breaches, too.

Get started with Enterprise-Class Security now, You can install Wordfence with these four best-practice steps:

  1. Sign into your own WordPress website. You’ll usually go to something like and sign-in

2. Replace with
your own website’s URL

3. Now that you’re signed in and ready to administer your own site, go to Plugins, Add New and do a search for ‘wordfence’ without quotes

5. Click the “Install Now” link and
Wordfence will be installed

When you decide to upgrade to the best WordPress Security
out there, simply upgrade to Wordfence Premium.

Install and Configure Django on a Linux Shared Hosting

Django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design. Built by experienced developers, it takes care of much of the hassle of Web development, so you can focus on writing your app without needing to reinvent the wheel. It’s free and open source.

  • Ridiculously fast – Django was designed to help developers take applications from concept to completion as quickly as possible.
  • Fully loaded – Django includes dozens of extras you can use to handle common Web development tasks. Django takes care of user authentication, content administration, site maps, RSS feeds, and many more tasks — right out of the box.
  • Reassuringly secure – Django takes security seriously and helps developers avoid many common security mistakes, such as SQL injection, cross-site scripting, cross-site request forgery and clickjacking. Its user authentication system provides a secure way to manage user accounts and passwords.
  • Exceedingly scalable – Some of the busiest sites on the planet use Django’s ability to quickly and flexibly scale to meet the heaviest traffic demands.
  • Incredibly versatile – Companies, organizations and governments have used Django to build all sorts of things — from content management systems to social networks to scientific computing platforms.

You will have a functioning Django site on your account that:

  • Loads a static homepage for the domain.
  • Loads the Django administration interface.
  • Uses a SQLite database.

Create A Python Application In cPanel

The Setup Python App feature allows you to deploy Python applications on your cPanel while running the Apache web server.

You can check the functionality by visiting the cPanel, Setup Python App.

Install and Configure Django

On the next page, you will be able to Create Application and check existing Web applications.

Install and Configure Django

After clicking Create Application you will be presented with the app creation menu:

If you wish to create a new Python application, you must specify the Python version, fill in the Application root, and the Application URL. Then click Create.

Optionally, you can also set up Application startup fileApplication Entry point and Passenger log file.

As soon as the environment is set, you can upload your application files to the application root directory.

When the application is created, you will be able to see the next page:

At the very start, you have the command necessary to enter your virtual environment. This is useful when you need to manually execute some commands either via SSH or with the terminal menu in cPanel.

To be able to do this, you need to enable Shell access as in this guide.

How to Configure the Django project

1) Login to cPanel.

2) You can see the option Terminal under the “ADVANCED” menu. Click the option to open the terminal.

3) If you are accessing the terminal for the first time, a screen will appear with a warning message. Please click on the button proceed.

4) This interface provides command line access to your account on the server. You can now manage the account using CLI

5) Use the command you noted in the above step to activate the virtual environment. For example:

# source /home/username/virtualenv/myapp/3.6/bin/activate

You need to replace username with your cPanel username

The command prompt now starts with (myapp:3.6) to indicate that you are working in the myapp virtual environment with Python 3.6. All of the following commands in this article assume that you are working in the Python virtual environment.

6) Type the below command to install Django:

# cd ~pip

# install django==2.1.8

You can verify the version of Django installed, with the following command:

# django-admin --version

7) Type the below command for creating a Django project:

# django-admin startproject myapp ~/myapp

8) To create directories for the static project files, type the following commands:

# mkdir -p ~/myapp/templates/static_pages 
# mkdir ~/myapp/static_files 
# mkdir ~/myapp/static_media

a. Find the ALLOWED_HOSTS line and then modify it as below. Replace with your own domain name:


b. Find the TEMPLATES block, and then modify it as below:

‘BACKEND’: ‘django.template.backends.django.DjangoTemplates’,
‘DIRS’: [os.path.join(BASE_DIR,’templates’)],
‘APP_DIRS’: True,
‘context_processors’: [

c. Locate the STATIC_URL line, and then add the below lines beneath it:

MEDIA_URL = ‘/media/’
MEDIA_ROOT = os.path.join(BASE_DIR, “static_media”)

STATIC_URL = ‘/static/’
STATIC_ROOT = os.path.join(BASE_DIR, ‘static_files’)

9) Open the ~/myapp/myapp/ file using the text editor. Delete the existing text and copy the below text into the file:

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from django.conf.urls import url
from django.views.generic.base import TemplateView

urlpatterns = [
url(r’^$’, TemplateView.as_view(template_name=’static_pages/index.html’), name=’home’),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

10) Open the ~/myapp/ file and do the following changes. Replace username with your own account username:

import myapp.wsgi
SCRIPT_NAME = '/home/username/myapp'

class PassengerPathInfoFix(object):
    Sets PATH_INFO from REQUEST_URI because Passenger doesn't provide it.
    def __init__(self, app): = app

    def __call__(self, environ, start_response):
        from urllib.parse import unquote
        environ['SCRIPT_NAME'] = SCRIPT_NAME

        request_uri = unquote(environ['REQUEST_URI'])
        script_name = unquote(environ.get('SCRIPT_NAME', ''))
        offset = request_uri.startswith(script_name) and len(environ['SCRIPT_NAME']) or 0
        environ['PATH_INFO'] = request_uri[offset:].split('?', 1)[0]
        return, start_response)

application = myapp.wsgi.application
application = PassengerPathInfoFix(application)

11) Use a text editor to create a basic index.html file in the ~/myapp/templates/static_pages directory.

The file can be as simple as a text file that says Hello world.

12) Type the following command:

# python ~/myapp/ migrate

13) Create and set up the superuser account:

  • For this, type the below command:

# python ~/myapp/ createsuperuser

  • Type the administrator username at the Username prompt and then press Enter.
  • Type the administrator e-mail address at the Email address prompt and then press Enter.
  • Type the administrator password at the Password prompt and then press Enter.

14) To collect the static files, type the below commands:

# python ~/myapp/ collectstatic

In case you are asked for overwriting existing files, type yes and then press Enter.

15) Restart the Python application in cPanel:

  • Log in to cPanel.
  • Click Setup Python App in the SOFTWARE section of the cPanel home screen.
  • Locate the correct application under the Existing applications and then click Restart.

16) Test the Django site:

  • Go to, where represents your domain name. The index.html file should load.
  • Go to, where represents your domain name. The Django administration login page should be displayed. Use the superuser credentials that you created earlier to log in.

If there a problem for the website to appear in your browser, run the file manually. For this, type the below command:

# python ~/myapp/

When you run this file, you should get any text output to the console. In case there are any errors, check the syntax in the configuration files.

That’s all! Now, you can easily install and configure Django on a Linux shared hosting account.

Setup Python App

The Setup Python App feature allows you to deploy Python applications on your cPanel while running the Apache web server.

You can check the functionality by visiting the cPanel, Setup Python App.

Install and Configure Django

On the next page, you will be able to Create Application and check existing Web applications.

Install and Configure Django

After clicking Create Application you will be presented with the app creation menu:

If you wish to create a new Python application, you must specify the Python version, fill in the Application root, and the Application URL. Then click Create.

Optionally, you can also set up Application startup fileApplication Entry point and Passenger log file.

As soon as the environment is set, you can upload your application files to the application root directory.

When the application is created, you will be able to see the next page:

At the very start, you have the command necessary to enter your virtual environment. This is useful when you need to manually execute some commands either via SSH or with the terminal menu in cPanel.

To be able to do this, you need to enable Shell access as in this guide.

You can change options like Python version, Application root, Application URL, Application startup file, Application Entry point and Passenger log file here.
After changing such options, please make sure to click the Save button on the upper right.

The Python versions available are 2.7 and 3.3, 3.4, 3.5, 3.6 and 3.7.

PLEASE NOTE: Python version switch can take up to 5 minutes.

The Application startup file is to specify the Python WSGI application entry point. It must be specified as a filename.
Application Entry point is there to set up a WSGI callable object for the previously specified startup file.

With the help of the Configuration files field you can install various modules through Pip. Under the Add another file… field you can enter the name of the given module and click Add.

If you click Delete, the corresponding module entry will disappear. If you click Edit, you can change the module in question.

Once you have added the module, you can click Run Pip Install and install the module in question from the drop-down.

You can also execute pip install commands directly under the virtual environment via SSH.

Also, you can execute python script commands from the web interface (e.g. you can install packages from specific repositories or control web applications by means of django-admin).

You can additionally set up Environment variables:

Click Add Variable and you will be able to set up Name and Value of the variable in question. After you have entered the correct data, click Done to create the variable.

NOTE: Changes will not be applied to the application environment until the Update button is clicked. All changes can be reverted by clicking the Reset button.

You also have the options to Stop App and Restart the application.

To delete the application, click Destroy. The application folder itself will remain unmoved.

Dealing with WSGI application issues

In some cases, apps may not run properly when the main application variable is called app. This is because WSGI software that we use to run Python on our servers requires the main application variable to be called application.

We will use the Flask application as an example here to make the application work:

1. Install Flask and all the other modules required for the app. It can be done in many ways:

  • Install modules manually one by one over SSH

This can be done using the standard Run Pip Install button described in this guide, or via SSH using pip install module command.

  • Install all the modules at a time with a requirements.txt file.

It can be done with the following type of command via SSH:pip install -r requirements.txt

  • Install all the modules with a file via SSH, if it is created for the application,. The usage of this option depends on the app in question.

2. Remove the default file under the application root folder.
3. Find the main script of the application in the application root folder. Search for the following line to find it:
from app import app
(it can be from src import app or from app import application, however from app import app is the most common way to write it). The main script is usually called,,, or
4. Rename this script to or set it in the Application startup file field within the Python App interface in cPanel.
5. Right below the import line (from app import app), insert this line:
application = app

The described actions should help fix an application that was not written with WSGI software in mind.

High Severity Vulnerability Patched in Ninja Forms

On April 27, 2020, the Wordfence Threat Intelligence team discovered a Cross-Site Request Forgery(CSRF) vulnerability in Ninja Forms, a WordPress plugin with over 1 million installations. This vulnerability could allow an attacker to trick an administrator into importing a contact form containing malicious JavaScript and replace any existing contact form with the malicious version.

We reached out to Ninja Form’s security team according to their Responsible Disclosure Guidelines and they replied within a few hours. The plugin was patched less than 24 hours after our initial contact, on April 28, 2020.

All Wordfence users, including both Wordfence Premium and free Wordfence users, are protected from XSS attempts against this vulnerability by the Wordfence Firewall’s built-in XSS protection.

Description: Cross-Site Request Forgery to Stored Cross-Site Scripting
Affected Plugin: Ninja Forms
Plugin Slug: ninja-forms
Affected Versions: <
CVE ID: CVE-2020-12462
CVSS Score: 8.8 (High)
Fully Patched Version:

The Ninja Forms plugin features a “legacy” mode which allows users to revert its styling and features to those of the plugin’s final 2.9.x version. As part of this feature, it adds several AJAX functions which appear to be intended to import forms and fields between the “legacy” mode and the default mode. While all of these functions used capability checks, two of the functions failed to check nonces, which are used to verify that a request was intentionally sent by a legitimate user. One function in particular, ninja_forms_ajax_import_form, allowed importing forms containing custom HTML:

add_action( 'wp_ajax_ninja_forms_ajax_import_form', 'ninja_forms_ajax_import_form');functionninja_forms_ajax_import_form(){if( ! current_user_can( apply_filters( 'ninja_forms_admin_upgrade_import_form_capabilities', 'manage_options') ) ) return;$import= stripslashes( $_POST[ 'import'] );$form_id= ( isset( $_POST[ 'formID'] ) ) ? absint( $_POST[ 'formID'] ) : '';WPN_Helper::delete_nf_cache( $form_id); // Bust the cache.Ninja_Forms()->form()->import_form( $import, TRUE, $form_id, TRUE );if( isset( $_POST[ 'flagged'] ) && $_POST[ 'flagged'] ){$form= Ninja_Forms()->form( $form_id)->get();$form->update_setting( 'lock', TRUE );$form->save();}echojson_encode( array( 'export'=> WPN_Helper::esc_html($_POST['import']), 'import'=> $import) );wp_die();}

As such, if an attacker was able to trick an administrator into clicking a crafted link, they could spoof a request using that administrator’s session and import a form containing malicious JavaScript into the site. Worse yet, it was possible to replace any existing form on the site with one of these imported forms by setting the formID $_POST parameter to the ID of an existing form.

Depending on where the JavaScript was placed in the imported form, it could be executed in a victim’s browser whenever they visited a page containing the form, whenever an Administrator visited the plugin’s Import/Export page, or whenever an Administrator attempted to edit any of the form’s fields. As is typical with Cross-Site Scripting (XSS) attacks, a malicious script executed in an Administrator’s browser could be used to add new administrative accounts, leading to complete site takeover, while a malicious script executed in a visitor’s browser could be used to redirect that visitor to a malicious site.

Vulnerability Disclosure Policies are Important

One of the reasons this plugin was patched so quickly was because the plugin’s team maintains a Responsible Security Disclosure Policy, often referred to as a Vulnerability Disclosure Policy. This allowed us to contact them directly with our full disclosure rather than spending days trying to find or verify the appropriate contact channel. While we have occasionally seen plugins patched in less than 24 hours in the past, responses like this are exceptional and indicate a serious dedication to security.

If you are responsible for any kind of software product or service, having a Vulnerability Disclosure Policy (VDP) not only improves your chances of being alerted to serious security issues, but also allows you to set expectations for your response. Most importantly, it reduces the risk of vulnerabilities in your products being prematurely or irresponsibly disclosed and attacked by bad actors before you have a chance to fix them. For these reasons, we strongly recommend implementing a VDP to improve not only the efficiency of your response to specific flaws, but also the general security of your product.


April 27, 2020 19:00 UTC – Our Threat Intelligence Team discovers and analyzes the vulnerability and verifies that our existing Firewall Rules provide sufficient protection against XSS.
April 27, 2020 19:24 UTC – We provide full disclosure to the plugin’s developer as per their Responsible Security Disclosure Policy.
April 27, 2020 20:27 UTC – We receive a response that a patch should be available the next day.
April 28, 2020 19:00 UTC – Patched version of the plugin released.