WordPress Plugin Security Testing Cheat Sheet
This cheat sheet was compiled by Dewhurst Security to record the knowledge gained when testing WordPress plugins for security issues for our clients. The security documentation provided by WordPress and found online for plugin security is sparse, outdated or unclear. This cheat sheet is intended for Penetration Testers who audit WordPress plugins or developers who wish to audit their own WordPress plugins.
This is a living document, feedback in the form of Issues or Pull Requests is very much welcomed.
Cross-Site Scripting (XSS)
Check if the following global PHP variables are echo'd to pages, or stored in the database and echo'd at a later time without first being sanitised or output encoded.
(Note: the list of sources above is not extensive nor complete)
Cross-Site Scripting (XSS) Tips
Unsafe API functions
The following functions can cause XSS if not secured:
https://blog.sucuri.net/2015/04/security-advisory-xss-vulnerability-affecting-multiple-wordpress-plugins.html https://make.wordpress.org/plugins/2015/04/20/fixing-add_query_arg-and-remove_query_arg-usage/ https://developer.wordpress.org/reference/functions/add_query_arg/ https://developer.wordpress.org/reference/functions/remove_query_arg/
define( 'DISALLOW_UNFILTERED_HTML', true );
Unsafe API methods (require sanitising/escaping):
Safe API methods (according to WordPress):
Safe code, prepared statement:
<?php $sql = $wpdb->prepare( 'query' , value_parameter[, value_parameter ... ] ); ?>
Note: Before WordPress 3.5
$wpdb->prepare could be used insecurely as you could just pass the query without using placeholders, like in the following example:
$wpdb->query( $wpdb->prepare( "INSERT INTO table (user, pass) VALUES ('$user', '$pass')" ) );
SQL Injection Tips
Unsafe escaping ('securing') API methods:
esc_sql()function does not adequately protect against SQL Injection https://codex.wordpress.org/Function_Reference/esc_sql
escape()same as above
esc_like()same as above
like_escape()same as above
Displaying/hiding SQL errors:
<?php $wpdb->show_errors(); ?> <?php $wpdb->hide_errors(); ?> <?php $wpdb->print_error(); ?>
PHP Object Injection
is_admin()does not check if the user is authenticated as administrator, only checks if page displayed is in the admin section, can lead to auth bypass if misused.
is_user_admin()same as above
current_user_can()used for checking authorisation. This is what should be used to check authorisation.
wp_redirect()function can be used to redirect to user supplied URLs. If user input is not sanitised or validated this could lead to Open Redirect vulnerabilities.
Cross-Site Request Forgery (CSRF)
wp_nonce_field()adds CSRF token to forms
wp_nonce_url()adds CSRF token to URL
wp_verify_nonce()checks the CSRF token validity server side
check_admin_referer()checks the CSRF token validity server side and came from admin screen