WordPress Plugin Security Review: SearchWP Live Ajax Search
For our 40th security review of a WordPress plugin based on the voting of our customers, we reviewed the plugin SearchWP Live Ajax Search.
If you are not yet a customer of the service, once you sign up for the service as a paying customer, you can start suggesting and voting on plugins to get security reviews. For those already using the service that haven’t already suggested and voted for plugins to receive a review, you can start doing that here. You can use our tool for doing limited automated security checks of plugins to see if plugins you are using have possible issues that would make them good candidates to get a review. You can also order a review of a plugin separately from our service.
The review was done on version 1.6.2 of SearchWP Live Ajax Search. We checked for the following issues during it as part of our standard review:
- Insecure file upload handling (this is the cause of the most exploited type of vulnerability, arbitrary file upload)
- Deserialization of untrusted data
- Security issues with functions accessible through WordPress’ AJAX functionality (those have and continued to be a common source of disclosed vulnerabilities)
- Security issues with functions accessible through WordPress’ REST API (those have started to be a source of disclosed vulnerabilities)
- Persistent cross-site scripting (XSS) vulnerabilities in the frontend portions of the plugin and in the admin portions accessible to users with the Author role or below
- Cross-site request forgery (CSRF) vulnerabilities in the admin portion of the plugin
-
SQL injection vulnerabilities (the code that handles requests to the database)
-
Reflected cross-site scripting (XSS) vulnerabilities
- Security issues with functions accessible through any of the plugin’s shortcodes
- Security issues with functions accessible through the admin_action action
- Security issues with functions accessible through the admin_init action
- Security issues with functions accessible through the admin_post action
- Security issues with import/export functionality
- Security issues with usage of the is_admin() function
- Security issues with usage of the add_option(), delete_option(), and update_option() functions
- Security issues with usage of the update_user_meta() and wp_update_user () functions
- Security issues with usage of the extract() function
- Proper usage of sanitize_callback when using register_setting() to register settings.
- Lack of IP address validation
- CSV injection
- Host header injection vulnerabilities
-
Lack of protection against unintended direct access of PHP files
- Insecure and unwarranted requests to third-party websites
- Any additional possible issues identified by our Plugin Security Checker
Results
We found the plugin contained several places where security could be improved, which are detailed below.
We contacted the developer about the results through their website on Monday. They replied the next day that they were evaluating the results and would get back to us. On Wednesday after that they release version 1.6.3, which addressed most of the issue. We notified of a remaining issue and that was addressed today with a further change to 1.6.3.
Improper Sanitization With User Input Used in Include Statement
In three locations, we found the GET or POST input “swpengine” was set to a variable with the value being sanitized using sanitize_text_field():
145 | 'engine' => isset( $_REQUEST['swpengine'] ) ? sanitize_text_field( $_REQUEST['swpengine'] ) : 'default', |
164 | $engine = isset( $_REQUEST['swpengine'] ) ? sanitize_text_field( $_REQUEST['swpengine'] ) : 'default'; |
207 | $engine = isset( $_REQUEST['swpengine'] ) ? sanitize_text_field( $_REQUEST['swpengine'] ) : ''; |
The first two pass the value to another plugin’s code. The third passes the value through multiple functions, which eventually leads to the value being part of specifying a file to be included. So it would partially control specifying a file whose code would be run. Through directory traversal, any file on the website could be loaded that way, which would usually permit local file inclusion (LFI) to occur.
In our testing, though, we found that the issue couldn’t be used to cause LFI to occur as the file to be included is checked to make sure it exists with the function file_exists() before it was included, which will return that a file doesn’t exist in a situation where directory traversal is used.
The issue was addressed by changing the sanitization function used to sanitize_key(), which will strip out what would be necessary for directory traversal:
145 | 'engine' => isset( $_REQUEST['swpengine'] ) ? sanitize_key( $_REQUEST['swpengine'] ) : 'default', |
164 | $engine = isset( $_REQUEST['swpengine'] ) ? sanitize_key( $_REQUEST['swpengine'] ) : 'default'; |
207 | $engine = isset( $_REQUEST['swpengine'] ) ? sanitize_key( $_REQUEST['swpengine'] ) : ''; |
It is also more restrictive sanitization than sanitize_text_field().
Lack of Protection Against Direct Access to PHP Files
Some of the plugin’s .php files that didn’t appear to be intended to be directly accessed contained protection against direct access, but others were missing that. We didn’t see anything that could be exploited in the files without the restriction in place, but restricting access to them would ensure that there isn’t any issue with that.
The issue was addressed by adding the protection to the files missing it.