Finding Vulnerabilities with Static Analysis and AI - code analysis visualization

How to Find Vulnerabilities in WordPress Plugins with Static Analysis and AI Tools

While the WordPress core is a piece of well tested and mostly secure project, the thousands of plugins and themes that are available in the WordPress ecosystem are riddled with vulnerabilities since they are not all developed nor tested by people who are well versed in security. In this blog we will talk about how to easily find vulnerabilities in WordPress plugins using static analysis tools that support PHP (such as Semgrep) and trying out AI Large Language Models for finding vulnerabilities.

Related: Eight-Year Study Shows the Dark Side of WordPress Plugins

The power of static application security testing

Since WordPress plugins are written in PHP and have source code available for download, it makes it much easier to find vulnerabilities using Static Application Security Testing (SAST) tools. These tools can parse the syntax of various programming languages, and construct an Abstract Syntax Tree (AST) which represents the structure of a program regardless of its language.

By analyzing the AST using a variety of heuristics and rules (such as “does this user input string go into a raw SQL statement?”), it can find vulnerabilities at blazing speeds since it does not need to execute the program to do so. Regular expressions are also used to search for language-specific vulnerabilities, by simply finding dangerous string combinations (such as the PHP shell_exec statement for potential command execution).

Using Semgrep to find vulnerabilities in WordPress plugins

Semgrep is a powerful rule-based SAST tool. It supports over 20+ languages and has hundreds of security-related rulesets. Semgrep can be installed using Python Pip by running:

Related: Enumerating WordPress Plugins at Scale

pip3 install semgrep

To download a WordPress plugin’s source code, simply find the plugin on wordpress.org/plugins and download the zip file. Then you can extract it into a folder which will contain all of its PHP code.

Now open a terminal in that directory with the PHP code and run semgrep on it:

semgrep -c auto .

Using -c auto will tell semgrep to automatically configure scanning rules based on the languages found. In this case of the plugin Easy Digital Downloads being scanned, it has picked up on PHP, JS and JSON files and has loaded 1040 rules to scan them:

Static analysis tool scanning PHP source code for vulnerabilities

As any scanning tools go, there will be a lot of false positives, and you’ll need to manually look through the output for real and impactful vulnerabilities.

AI-powered code analysis detecting security flaws in WordPress plugin

It identified multiple vulnerabilities in the import-functions.php file, namely a file name based on user input and an insecure object instantiation with the class name based on user input. Looking at the first bug, we see here that a $_REQUEST[‘upload’][‘file’] parameter in a file upload request is being used as-is without checking for a relatively safe path. We should dig into the source code to see how that value is used:

Vulnerability detection results from automated static analysis scan

It looks like the only sanitization the file path goes through is the WordPress sanitize_text_field function, which according to the documentation, checks for invalid UTF-8, removes all whitespaces and escapes dangerous HTML characters such as tags:

Code flow analysis diagram showing tainted data propagation

What it does not do is strip away payloads such as ../ by calling functions like realpath, meaning it could be insufficient checking for the file path and lead to a path traversal vulnerability. Whether or not this is exploitable to create meaningful impact (such as remote code execution or information leakage) needs further testing and validation.

You can also write your own semgrep rules to test for different types of vulnerabilities. See this GitHub repo for more example semgrep rules for WordPress. To run scans on code in the current directory using rules you’ve made, just specify the path to your rules with -c:

semgrep -c ./path/to/your/rules .

Using AI to find vulnerabilities in WordPress plugins

Another way to identify potentially vulnerable code is using AI machine learning models. There are lots of models that are trained to detect vulnerable code across multiple languages, for example the CodeBERT UniXcoder by Microsoft (published in 2022), which is based on the transformer architecture. A tool called suspicious uses that model to detect suspicious tokens and highlights them in a file, with completely offline processing. To install suspicious, run:

pip3 install suspicious

We can then run suspicious on a file of our choice inside the WordPress plugin:

sus includes/admin/import/import-functions.php

On the first run, it will start downloading the model so that it can use it for offline processing. Then it will analyze the file and when done, open the browser with a results report.

Comparison of static analysis tools for WordPress security testing

We can see that it highlights important / suspicious keywords such as url, list, importer etc., but does not really find specific vulnerabilities. Like all transformer models that operate on string data, it’s based on token prediction, and it simply highlights the tokens that are prevalent in its model. So far, not very helpful.

Next, we test a modern OpenAI language model. We prompt it with:
“Find vulnerabilities in this PHP code in a WordPress plugin:” and then paste the entire source file.

It identified 7 different key points: nonce verification, file upload handling, class instantiation, user permission, data mapping and processing, and security headers. Here’s the start of it’s output:

It identifies some similar vulnerabilities to semgrep (namely the file upload issue) and the class instantiation issue. However, it did not pick up on the fact that sanitize_text_field does not actually sanitize path traversals in the file name (that was only discovered upon manual code review of the semgrep output). On the class instantiation bug, it did pick up that edd_importer_is_class_allowed is the mitigation, which would make it a non-issue; yet it was listed as a bug anyway.

On the nonce verification, it detected that wp_verify_nonce was used to prevent CSRF, and then added “ensuring nonces are used correctly and are not reused is essential”, which is just a generic comment on another non-issue, as best-practise of using wp_verify_nonce is followed in this code snippet.

The rest of the “findings” are more or less the same: they are general sentiments that do not point to specific vulnerabilities, and are only useful for “guiding” the analyst on which areas to look for bugs. For example, we can follow its advice and go through each instance of wp_send_json_* calls to check for sensitive data disclosure.

ChatGPT was also helpful in providing some suggested improvements. The most specific suggestion was to use finfo_file, which can validate the file’s actual content against the MIME type specified by user input. However, it did not detect that the code called mime_content_type instead, which achieves the same effect with an easier API usage. Other suggestions are generic at best (such as “sanitize and validate inputs”, which can apply to any code).

Further Reading

Conclusion

In conclusion, both SAST and AI tools can aid vulnerability identification in WordPress plugins, to varying degrees of success. The human analyst can use those tools to focus on specific areas, but still needs to triage the outputs to validate whether they are real vulnerabilities; the entire process cannot be automated with 100% accuracy.

With the ongoing improvements in SAST and AI tooling, WordPress plugins are under the watchful eyes of public security researchers more than ever. That’s why it’s important to watch for vulnerabilities creeping into your WordPress plugins. To run a scan on your website today, visit wpsec.com and get free instant access to your online security scan results.

Leave a Comment

Your email address will not be published. Required fields are marked *