The Plugin Security Scorecard Helps to Identify Insecure WordPress Security Plugins
While our new Plugin Security Scorecard provides security grades for all types of WordPress plugins, there is an extra focus on security plugins. As security plugins often are as much of a problem for security as a solution. Some of that focus comes in the form of extra data about problems in security plugins, which we manually create. We have generated that data for a lot of popular security plugins, but as other security plugins get checked we then check those to provide more accurate grades for them in the future. While looking at one such plugin, we saw the value that tool can provide even without having that data in place. It also shows why that additional focus can be important.
A plugin named Magic Login was checked with the tool yesterday. That is a plugin for implementing passwordless login. So a plugin where security is critical, as poorly implemented security could allow attackers to gain access to any WordPress account. That plugin has 1,000+ active installations. When it was graded yesterday it received a C+, not a great grade. Here are the issues the tool identified with it yesterday, that lead to that grade:
- The PHP function filter_input() is used without a filter, so it doesn’t do any filtering.
- The WordPress escaping function esc_url_raw() appears to be being misused. According to its documentation, it should only be used to sanitize a URL for database or redirect usage.
- The plugin doesn’t contain a security.txt file (or alternatively a SECURITY.md or SECURITY-INSIGHTS.yml), which would provide information on how to report security issues to the developer.
- The plugin isn’t listing in a security.txt file where the results of a security review that has been done of the plugin can be found. A well done security review would provide a good measure of the security of the plugin at the time it was done.
The first line of description on the WordPress Plugin Directory for the plugin is: “Easy, secure, and passwordless authentication for WordPress.” Reading the rest of the description, we found the developer provides no evidence the plugin is truly providing secure authentication. That kind of strong security efficacy claim is something we checked for manually with security plugins. A good security review could provide such evidence, but as the issue list notes, they are not linking to one.
Quickly checking over the plugin, we found that the plugin has a pretty glaring security issue. That is something that should have been caught if a security review was done. Before we get to that, let’s look at two code issues the tool warned about, which suggest the developer doesn’t have the best grasp of securing a WordPress plugin.
filter_input()’s Odd Misuse
One of the issues identified was the misuse of the PHP function filter_input(), where it doesn’t do any filtering. Here are the lines of the code that caused that:
111 112 113 114 115 116 | $settings['is_default'] = boolval( filter_input( INPUT_POST, 'is_default' ) ); $settings['add_login_button'] = boolval( filter_input( INPUT_POST, 'add_login_button' ) ); $settings['token_ttl'] = absint( filter_input( INPUT_POST, 'token_ttl' ) ); $settings['token_validity'] = absint( filter_input( INPUT_POST, 'token_validity' ) ); $settings['auto_login_links'] = boolval( filter_input( INPUT_POST, 'auto_login_links' ) ); $settings['enable_ajax'] = boolval( filter_input( INPUT_POST, 'enable_ajax' ) ); |
133 | $token_interval = sanitize_text_field( filter_input( INPUT_POST, 'token_interval' ) ); |
It turns out that in each instance, there is a sanitization or validation function being used after using that function. So why use that function first when it isn’t doing anything? It isn’t that the developer always uses that to bring in user input to the code. Here is an example without that:
122 | $settings['token_ttl'] = absint( $_POST['token_ttl'] ) * 1440; |
What is going on there doesn’t seem to make sense and is concerning to see from a security plugin.
esc_url_raw() Misuse
Another issue identified was misuse of a WordPress escaping function, esc_url_raw(), which is only supposed to be used to sanitize a URL for database or redirect usage. In the plugin, it is being used when the value is output instead:
36 | <li><a href="<?php echo esc_url_raw( FAQ_URL ); ?>" target="_blank"><?php esc_html_e( 'FAQ', 'magic-login' ); ?></a></li> |
esc_url() should be used there instead. That issue is also not great to see from a security plugin.
Glaring Security Issue
In the file /includes/admin/dashboard.php, the plugin registers the function save_settings() to run during admin_init:
34 | add_action( 'admin_init', __NAMESPACE__ . '\\save_settings' ); |
That makes it accessible to even those not logged in. If it is saving settings as the function hints at, then access needs to be properly restricted. The function does save settings, but access isn’t properly restricted.
Any security review of a WordPress plugin should check on the security of any functions registered to run during admin_init because of the repeated and well-known vulnerabilities caused by insecurity in those functions.
The only access restriction is that the request to access the code has to come from someone logged in to WordPress:
91 92 93 94 95 96 97 98 | function save_settings() { if ( ! is_user_logged_in() ) { return; } $nonce = filter_input( INPUT_POST, 'magic_login_settings', FILTER_SANITIZE_SPECIAL_CHARS ); if ( wp_verify_nonce( $nonce, 'magic_login_settings' ) ) { |
There is a nonce check to prevent cross-site request forgery (CSRF), which in normal circumstances would limit access to those only intended. But as the WordPress documentation states clearly, it shouldn’t be relied on for that:
Nonces should never be relied on for authentication, authorization, or access control. Protect your functions using
current_user_can()
, and always assume nonces can be compromised.
The soundness of that advice was on display when we found a plugin with 200,000+ installs from a security provider has vulnerabilities because the developer compromised the nonces themselves. (We ran across that because we were vetting if the developer had really done a security review of their plugin.)
In this case, the nonce isn’t compromised, so there is a vulnerability. But that security issue shouldn’t be there.
Preliminary Grading Seems Good
While our scorecard doesn’t have the capability to detect that security issue, with the things it could check, it provided a grade that seems to provide a reasonable warning about the plugin’s insecurity. Resolving those issues would included there being a security review being done. If it was well done, it should have caught that issue. If it wasn’t well done, then our additional checking of security reviews for graded plugins would catch that and, in turn, warn about that.
Additional Issues Lower Grade Further
Our manual checking identified two additional issues in the plugin:
-
The plugin is being marketed with a strong claim (or claims) of efficacy without citing evidence that backs up the claim.
-
The plugin is spreading misleading information about brute force attacks against WordPress websites, which are not actually happening, and causing the WordPress community to not focus on real security threats.
With those included, that would bring down the grade to a D+ if the plugin is rechecked without any of the previously identified issues being addressed. Considering that security plugins shouldn’t have their own security issues, that also seems like a fair grade.