I originally authored this post on WP Realm, but I moved it back here after that website folded.

WordPress has an irritatingly bad reputation for security. This is mostly due to misinformation and partly due to WordPress taking the rap for flawed security either at server level, or at the theme/plugin level. Server security issues can be reduced by using a well respected webhost such as HostGator or WP Engine. Theme and plugin security can be much harder if you are unable to security audit the code you are using. A quick search through the WordPress plugin repository by a trained eye can show up a scary proportion of plugins with security flaws. Unfortunately, unless you understand how security attacks occur and what type of code causes security flaws there is no way to know if a plugin is usable or not.

Unfortunately, providing a comprehensive lesson on web security in a single blog post is impossible. The subject of security is broad and new ways to exploit code are constantly being developed. To stay on top of the world of internet security is a very tricky task, but we can at learn some basic techniques for analysing code to determine if any major flaws exist. This blog post is intended to teach you how to see some simple security flaws. If you see these types of flaws in a plugin or theme, you should steer well clear of it.

User submitted data

The most common attack vector for hacking WordPress via plugins and themes is cross site scripting (XSS). This form of attack involves injecting JavaScript into a site. To do this, users need to submit data to your site. If users can never submit data to your site, then your site should be considerably less vulnerable to XSS. A site with no user submitted content would unfortunately be a very boring website.

WordPress core internally uses aggressive data sanitisation on all data submitted by users. The only user level at which WordPress takes a more relaxed approach is for administrators (or super admins on multisite) since those users are considered “trusted”. If a member of the public submits a blog comment, WordPress parses the text input through the wp_kses() filter to remove all potentially nasty code. Plugins and themes should use the same aggressive approach to data sanitisation, but unfortunately this is often not the case.

Based on this, it is clear that any data which is submitted by a user must be throughly sanitised to ensure that no nasty code gets through. Unfortunately, finding that un-sanitised data is very difficult.

Finding un-sanitised inputs

The four most common forms of un-sanitised inputs found in WordPress plugins/themes are raw query strings, post requests and server variables. It is critically important to ensure that any of these data inputs are scrubbed clean of all potentially nasty code before doing anything with them. If a value to be a string of text with no HTML, then all HTML should be stripped out, if the value is expected to be a number, then a check should be in place to ensure that the value is indeed numeric and doesn’t contain any malicious attack code. Never allow any data to interact with a plugin or theme which doesn’t match the format expected.

Query strings

$_GET and $_REQUEST variables can be used to access data from query strings in URLs. If a plugin outputs the contents of a $_GET variable onto the page, they will have the ability to send other users to a page which may potentially execute JavaScript included via a query string.

A prime example of this type of security attack is in themes which display search strings back to the user who performed the search. The following is an example of a totally un-sanitised output, which could be used to inject JavaScript into the page. A regular search will never cause problems with this type of code, but hackers simply need to send a link to the administrator of the site which uses carefully crafted javascript in the URL, and that JavaScript will be executed in the administrators browser without their permission.

https://gist.github.com/3848461

The correct way to display the search query back to the user is to sanitise it first. WordPress provides a range of standard functions for sanitizing different types of data inputs. You can read more about the various options on the Data Validation page at WordPress.org. The appropriate sanitization for an input field is esc_attr() which is intended for escaping attributes.

https://gist.github.com/3848471

Conveniently, WordPress goes one step further and includes a function specifically for search queries called get_search_query() which can be used as follows.

https://gist.github.com/3848476

Post requests

$_POST and $_REQUEST variables are used to access the values of submitted form fields. Form submission data must always be sanitized to ensure that malicious code is removed. It is important to ensure that the data is cleaned before using it for anything. Data must not be added to the database then sanitised afterwards as by that stage it may be too late to stop an attack. It is unfortunately common to see code resembling the following in WordPress plugins and themes.

https://gist.github.com/3848477

In this scenario, the raw post request is dumped directly into the database. The plugin or theme will then likely output that code to the end-user either in the admin panel or the front-end of the site. This would be a security catastrophe and must be avoided at all costs. Assuming that the data being submitted must be an integer, then the following code will ensure that the data is a valid integer before adding it to the database.

https://gist.github.com/3848479

If this submitted form data is perhaps a comment with some HTML, then it should be sanitised with a function which removes any potentially evil scripts; the wp_kses() function is ideal for this purpose.

https://gist.github.com/3848482

Server variables

Even developers who understand the concept of sanitising user submitted data often fail to appreciate the significance of displaying some server variables to site visitors. There are a range of server set variables which can be accessed from within PHP. Unfortunately, some of these can be manipulated by people wishing to display malicious code on your website. Through careful crafting of URL’s, the $_SERVER[‘PHP_SELF’] variable can be manipulated to display JavaScript on your site, and as we discussed earlier, you need to ensure that non-trusted users never have the ability to load custom JavaScript on your site. $_SERVER[‘PHP_SELF’] is used to determine the current page URL, but if the current page URL is not what you expected, then this can lead to alarming results, including the potential injection of JavaScript into pages.

Mark Jaquith wrote an excellent post on this type of security flaw. An examples given by Mark included use of $_SERVER[‘PHP_SELF’] in form fields as follows.

https://gist.github.com/3848484

It is rare to ever require $_SERVER values in WordPress plugins or themes, however if they are required then it is absolutely critical to escape/sanitise them. Since they are usually used within URL’s, the standard way to escape them is via the esc_url() function.

https://gist.github.com/3848488

Most form submissions can be submitted back to the current URL, voiding the need for using a $_SERVER variable at all.

https://gist.github.com/3848492

More security tips coming soon

These are only some of the most common security flaws found in WordPress plugins and themes. Also common are failures in user permission and user intention checks, which will be covered in a future article.