How to Prevent Authentication Bypass Vulnerabilities
The WordPress Security Learning Center
How to Prevent Authentication Bypass Vulnerabilities

2.4: How to Prevent Authentication Bypass Vulnerabilities

Advanced
Updated January 25, 2016

Authentication bypass vulnerabilities are one of the less common vulnerabilities we see, but they are also one of the easiest to accidentally create as a WordPress plugin author. So we thought it would be useful to include a short lesson on common pitfalls that lead to these kinds of vulnerabilities.

Beware of is_admin()

There is a function in the WordPress API called is_admin(). If you are a developer who is new to WordPress development, it’s easy to assume that this function checks if a site visitor is an admin. That is not what this function does.

The is_admin() function actually checks if the administrator panel is being displayed. It is a badly named function and we have seen multiple developers make the mistake of using this function to try to verify if a site visitor has access to an administrative function.

A common mistake is to create code that looks like the following:

if(is_admin()){ //Incorrect check to see if admin
  add_action('wp_ajax_your_function', 'yourClass::yourFunction');
}

The is_admin() function is incorrectly used above to check if a visitor is an admin. That is not what it does. If yourClass::yourFunction() performs an operation that should only be accessible to an administrator, then this is an authentication bypass vulnerability.

How to Correctly Check Permissions

To correctly check if a user should have access to a function, it is important to understand a bit about WordPress permissions. When you create a WordPress user, they have a certain role. There are six predefined roles in WordPress:

  • Super Admin
  • Administrator
  • Editor
  • Author
  • Contributor
  • Subscriber

The above roles are in descending order of how much access they have. These roles have what WordPress calls ‘capabilities’ or things they can do. On a single WordPress site, the ‘super admin’ and ‘administrator’ role are the same. ‘super admin’ has some extra capabilities on a WordPress multi-site installation.

The table below gives you an idea of what each WordPress role is able to do.

WordpressUserRolesTablepg1_1340px

The API is fully documented on WordPress.org.

To check if a user is an administrator on a single-site WordPress installation, you can change our above code to the following:

if(current_user_can('manage_options')){ //INCORRECT on multi-site. See below.
  add_action('wp_ajax_your_function', 'yourClass::yourFunction');
}

In the above code we check if the user has the ‘manage_options’ capability. Only administrators and super admins in WordPress have this capability.

There is a problem with the above code. If your plugin is installed on WordPress multi-site, both administrators and super-admins have the ‘manage_options’ capability. If you are providing a function that only Administrators can access on single-site WordPress and only Super Admin’s can access on WordPress multi-site, you can change the code to the following:

$hasAccess = false;
if(is_multisite()){
  if(current_user_can('manage_network')){
    $hasAccess = true;
  }
} else {
  if(current_user_can('manage_options')){
    $hasAccess = true;
  }
}
if($hasAccess){
  add_action('wp_ajax_your_function', 'yourClass::yourFunction');
}

To be extra safe, you may want to add these checks into a function called hasAccess() that you define. Then you should do the check before you define the privileged action and do the check again inside the function that performs the privileged operation. While this may not seem performant, it will protect you if you decide to use the privileged function elsewhere in the code.

The check we do above checks if the current user can ‘manage_network’ if it’s a multi-site installation. Only a Super Admin on multi-site can manage_network. If it’s a single-site, it checks if the user can manage_options, which only Administrators on single-site can do. This ensures that only Super Admin’s on multi-site and Administrators on single-site can call your privileged function.

Conclusion

Now that you know how to correctly check permissions in your WordPress plugin or theme, you can create a function in your code that checks permissions correctly. Then you can liberally sprinkle that function around your code wherever you perform a privileged operation to ensure that only users with the correct access level have permission to perform your privileged operations.

Did you enjoy this post? Share it!

The WordPress Security Learning Center

From WordPress security fundamentals to expert developer resources, this learning center is meant for every skill level. Get serious about WordPress Security, start right here.