
Does WordFence protect my WordPress site as well as everyone claims?
On this page
This article was published on February 20, 2019 on damianstrobel.de - as part of a consolidation, these articles that have some relevance to IT security are also being included in the DSecured blog.
In my daily work, I keep encountering clients who rely too heavily on WordFence and similar tools. What’s missing is the understanding that even though everything seems perfectly secured, they still got hacked - because “WordFence was supposed to prevent that.” The marketing departments behind WordFence are simply doing an excellent job.
First of all: WordFence and similar tools do have their justification and can be quite useful. What bothers me, however, is the firm belief that these PHP plugins can prevent attacks on your own PHP site and offer almost perfect security. Some people even believe that installing WordFence means they don’t need to worry about security anymore. Such statements usually come from people who have virtually NOTHING to do with IT security, couldn’t recognize a security vulnerability in code, and don’t generally deal with the topic - instead, they just repeat things they’ve heard somewhere, or they’re being paid to say them.
So what can we do? What better idea than to install WordFence and simply test which types of security vulnerabilities it can effectively block?
We Need Different Types of Security Vulnerabilities
I programmed a simple WordPress plugin that contains several popular and well-known security vulnerabilities. These include:
- Cross Site Scripting (XSS)
- SQL Injections
- PHP Object Injection
The plugin allows each of these vulnerabilities to be exploited via $_GET, $_POST, $_COOKIE, or $_SERVER (see the excursus below). I left out $_REQUEST and $_FILE because $_REQUEST already includes the data from the first three methods mentioned. For demonstration purposes, pure upload operations weren’t of interest to me either, so $_FILE was also omitted.
Excursus – Data Transmission in PHP:
In a PHP web application, there are several ways to send data/information to the server. These include the ones mentioned above. Below is a brief explanation of each method:
- $_GET: URL parameters are found in this array, meaning a URL like index.php?var=123&test=1337 will have its parameters available under $_GET['var'] and $_GET['test'].
- $_POST: Form data - when you fill out a form (e.g., email or password fields), these inputs are stored in this array.
- $_COOKIE: As the name suggests, cookies set by the website are stored here. A cookie usually has a validity scope and an expiration date.
- $_SERVER: Server information and certain parts of the request are stored here - for example, your IP address, the requested path, the user agent, and dozens of other details.
- $_FILE: Upload forms - data related to file uploads handled by a PHP script will be found here.
- $_REQUEST: This array gives access to all data contained in $_GET, $_POST, or $_COOKIE.
The three selected methods for attacking websites - regardless of whether they’re WordPress-based or not - are extremely common. XSS and SQLi are probably the two most frequently seen attack types. It’s worth looking at, for example, exploit-db and searching for WordPress. The last type of vulnerability is perhaps the most interesting one. Few people are familiar with it, and it’s anything but trivial to exploit - it heavily depends on the system in which it’s found.
Does WordFence Protect Against XSS Attacks?
Partially. The WordFence filter is relatively good. If the payload (HTML code or JavaScript code) is transmitted via $_GET (e.g., URL parameters) or $_POST (usually form inputs, searches, etc.), WordFence protects fairly effectively. Things get interesting, however, when the payload is transmitted via a cookie or a server variable - in those cases, WordFence offers no protection at all. For testing, I used the following code; with a little modification, you could, for example, steal cookies with it:
"><script>alert(document.cookie)</script>

Some may say: “But XSS never works via $_SERVER/$_COOKIE.” That’s wrong - and the funny thing is that WordPress or a plugin itself provides proof to the contrary. In fact, this is quite well-known - User Login-Log had an XSS vulnerability in early 2017. To exploit it, you simply had to manipulate your User-Agent and then attempt to log in (successful or not). The value was stored and later displayed in the WP Admin table - executing the payload. This could be used to steal the credentials of a logged-in WP administrator (and do many other fun things). Even plugins like All in One SEO were affected.
My conclusion: When it comes to protection against XSS, WordFence is far from bad - but it’s certainly not perfect.
Does WordFence Protect Against SQL Injections?
SQL Injections are very interesting and occur quite often - especially when developers aren’t familiar with $wpdb and write their own queries. In this type of attack, the developer allows user input to enter a database query without proper sanitization. For example:
SELECT option_name FROM options WHERE option_id = [user input]
With the injection of "-1 UNION SELECT CONCAT(',',email,password) FROM user_table WHERE id=1" at the spot where [user input] is located, you cause the output to be, instead of "option_name", the combination of the email and password of the user with ID 1. And even if there is no direct output, you can infer results via blind injection. In the wild it looks something like this: SQL Injection in the Mail Masta plugin
For this case I also built a simple query and allowed data to be injected into the query via the four methods mentioned above. For example, an illustrative $_GET-based snippet looked like this:
global $wpdb; $results = $wpdb->get_results('SELECT option_id FROM wp_options WHERE option_id = ' . $_GET['damian-2'], OBJECT); echo '<pre>'; print_r($results); echo '</pre>';
Basically a query for the option ID based on the ID itself. Nonsensical, but perfectly sufficient. I expect the ID as output.
Here it gets quite interesting. Without peeking into WordFence's source code, I tried a lot and found that more complex attacks are consistently blocked, while simple informational queries pass through without trouble. For example:
-1 union select version()
The method (GET/POST/COOKIE/SERVER) does not matter here - simple queries always get through. WordFence probably uses some kind of scoring system to decide when to block for safety.
The following query is also blocked:
-1 union select 2 from wp_options
That’s already good. I tested $_GET and then $_POST. Now for the classic again: injection via $_COOKIE. This also occurs occasionally in the wild. And lo and behold… nothing is blocked. The same applies to $_SERVER.

In the picture you can see my username and the password hash (which I redacted). You can also see, on the right side of the browser window, what content the test cookie contained.
My conclusion: The majority of attacks are transmitted via POST/GET and are probably blocked quite successfully. If something can be injected into a query via a cookie or a server variable, WordFence won’t help you. One could still try to get the password via GET/POST. I wouldn’t be surprised if there’s a way to bypass the defenses. It’s also important to know that it very much depends on the type of SQL injection. In my case I used one where additional data is appended after the "WHERE". For the extremely rare case where you can modify the table itself (i.e., no "FROM" or "UNION" is needed), you may well succeed via GET/POST as well.
PHP Object Injection? What is that?
I could write a lot here, but a link is simple and there are great sources on the topic: https://www.owasp.org/index.php/PHP_Object_Injection
Does WordFence Protect Me From PHP Object Injections?
Some of you might say you’ve never seen this kind of vulnerability in WordPress. Currently there is no entry in Exploit-DB. That’s not because they don’t exist - it’s more because they are so dangerous that any reasonable pentester reports them and does not write and publish an exploit. If anything, these attack vectors are usually only described very roughly. A nice example is such a vulnerability in Piwik: Piwik <= 2.16.0 (saveLayout) PHP Object Injection Vulnerability
Concretely, in the case of WordPress I can report that a known theme had such a vulnerability which will be fixed in the near future. I won’t give details, of course, but in a hacked client site I was able to inspect the source code and found a POI vulnerability which I reported. Even though I did it for free and asked for nothing, the company wants to pay a four-digit "bug bounty". That doesn't show how great I am - it shows that companies understand what such a vulnerability means, especially in software used by thousands.
So let’s see how WordFence performs on this topic. Again I use a trivial example:
class poi { public $test; public function __destruct() { eval($this->test); } }
You see a simple object whose destructor is capable of executing code. If I have access to $test and somehow trigger the destructor, the code in $test will be executed. Sounds easy - but in reality it is not. My class is super simple and serves for illustration. In real life it hopefully doesn’t appear in exactly this form. Typical use cases are, for example, logging functions that are placed in a destructor. When the object is destroyed, that method is called. To exploit a POI you can aim at the unserialize function. It has some interesting properties. I quote from the PHP manual:
Warning: Untrusted user input should not be passed to unserialize(). Deserialization may instantiate objects and trigger autoloading, potentially exposing code that can be executed. A secure, standardized exchange format such as JSON (via json_decode() and json_encode()) should be used if serialized data must be exchanged with the user.
Which is of course usually ignored.
Tip: If you’re curious, search your plugins and themes for "unserialize" or even "maybe_unserialize". If you find a spot like that, you can try to investigate further and see whether it's possible to inject your own data there. BUT: the mere presence of the function is not a vulnerability - it can be used safely (see the function's second parameter).
To exploit something like this we must find unserialize usage and get our data there. In my case it was stupidly simple:
$test = unserialize($_GET['data']);
Long story short:
yourwpsite.de/index.php?data=O%3A3%3A"poi"%3A1%3A%7Bs%3A4%3A"test"%3Bs%3A10%3A"phpinfo%28%29%3B"%3B%7D
Nicely formatted it looks like this:
yourwpsite.de/index.php?data=O:3:"poi":1:{s:4:"test";s:10:"phpinfo();";}
The data is obviously passed via the URL to PHP and ends up in unserialize. The script then terminates and just before that the object is destroyed/deleted - the point at which the destructor is called.
WordFence is currently unable to detect and mitigate such an attack.
The problem is/was that the CMS/system must contain another class with a magic function whose contents are of "interest". If you are resourceful you will almost always find something. Here is an example in an ancient WordPress version: example. You can of course use plugins and themes (or their classes) - there you're usually lucky.
Excursus: PHP Object Injection with concrete examples
The operation and possibilities of this attack depend heavily on which PHP version you are running. The older the version, the worse. Newer versions do bring improvements, but not as much as this linked analysis nicely shows. Relatedly, check out an article by a longtime friend (from whom I learned a lot :P): How we broke PHP, hacked Pornhub and earned $20,000
Or skip it all and watch this talk from the last CCC (Chaos Computer Club). Then you'll see what's possible with unserialize - regardless of which classes the attacked system provides.

My conclusion: WordFence does not protect you from complex attack methods. Don’t kid yourself!
General Notes on WordFence and Similar Tools
These "firewalls" protect you from certain attack scenarios because they know concrete attack signatures. New attacks or atypical paths are usually unprotected. You must also understand that WordFence is a plugin running within WordPress. If you have a script on your server that can be hacked, WordFence will not protect you at that level. WordFence also does not protect components used by plugins and themes that are not directly part of the system. Examples include upload scripts (always a bad idea) or the old Timthumb.
WordFence and external upload/download scripts
Excursus: Developers of "premium plugins" especially tend to ignore the authentication mechanisms that WordPress provides. The result is plugins that include upload functionality, which is then attached via an external file. The problem is that this file is accessible to everyone and can be used to upload files. You might not even see an upload form. I mention this kind of "vulnerability" because it’s a classic and a good example of why WordFence can’t address it - those upload files don’t live inside the WordPress system. Some examples:
- Arbitrary File Upload in Gravity Forms 1.8.19
- Uploadify
- Revslider
- Zen Mobile App Native (removed for that reason)
- Mobile friendly App-Builder by Easytouch v3.0
Proper file permissions would help against this. If the attacker cannot write anywhere, such an attack is of little use. I’ll say more about that in the next section.
The opposite of such vulnerabilities are plugins that allow files to be downloaded. These are fairly rare, but known cases share the trait that the scripts are also not part of the system - thus WordFence has no chance to protect there either.
Depending on the developer of a plugin or theme, WordFence may not protect you AT ALL. You regularly see developers using $_REQUEST. Why is that interesting? I showed above that WordFence practically doesn’t check cookies. The content of a cookie is also present in $_REQUEST. Great, right? 😉 I don't need to say more.
If you know this, then WordFence is not bad. My intention is not to badmouth it - even though that is how it may sound at first. I only want to show that WordFence has its limits. Don’t disable and delete it now. It has excellent monitoring features and is certainly better than nothing. But it does not protect you as perfectly as some marketing departments claim.
There are much better and more efficient ways to protect yourself.
“WordFence scanner finds all dangerous things…”
Sure? If you’re curious, you can find a .mo file HERE. This file is a German binary language file for WordPress. It contains a backdoor that purposely abuses pure WP core code to execute code. You only need to download it. Then upload the file to the wp-content/languages folder and select the new language as the default. The file intentionally produces errors in the system so you will immediately notice that something is wrong. I did that on purpose! Once the new language is activated, you can execute arbitrary PHP code via yoursite.de/index.php?d=[YOUR CODE].
I built the backdoor to accept input via $_GET so WordFence would (hopefully) have an easier time detecting the attack. If you like, you can use a hex editor to switch $_GET to $_COOKIE and then you’ll have:
- a backdoor that the WordFence normal scan does not find (try it!)
- a way to execute code bypassing WordFence (if it is activated)
The WordPress security team has already been informed and this will be fixed in an upcoming update. I publish this only because exploiting it requires server access anyway. If you have that, you usually have many other problems as well.
Also: I’ve seen this in the wild. There are other non-trivial methods to hide backdoors so that they often remain undetected - even after a "complete system reinstall" with data migration. A "complete system reinstall" is not a guarantee that everything is now secure!
The Classic - File Permissions, User Rights, Strong Passwords
Although it’s less convenient: separate the PHP and FTP users and give the PHP user read-only rights (except maybe specific folders) and the FTP user write rights. You will have to enter the FTP password during system updates, but you ensure that a successful attack (e.g., via RCE) cannot write to the filesystem. With a good password you don’t have to worry about brute-force attacks. If you want, add an htaccess to the WP-Admin and enjoy extra performance because bots won’t keep trying to log in.
Specialists among us can also disable PHP inside writable folders (e.g., wp-content/uploads). Then you might be able to write files there but never execute them. I’ve already written about this in my article "WordPress hacked".
If you also don’t update your sites, sooner or later you will be hacked - with or without WordFence.
Of course, file/user permissions do not protect against database access, so using WordFence is not unreasonable. But you must keep in mind that WordFence has its little weaknesses. If a vulnerability is "unfortunate" the attacker will manage to get your database data despite WordFence.
Choose good web hosts!
Therefore even more important: the choice of a good host. My current recommendation to clients for normal webspaces is All Inkl. There you can create subaccounts with file/user permissions easily. Another plus is that SSH is available. That means people like me who maintain a site can work much more efficiently via SSH. File changes, updates, log processing/analysis are more enjoyable. If you need a managed server, consider offers from DomainFactory and Webgo. Both offer quotas - essentially a way to separate individual websites from each other. The most common mistake people make is renting such servers but not using these features. The consequence: one site gets hacked and the malware spreads through the whole system. Unnecessary and negligent.
Conclusion
In a few hours I tested simple attack methods on a live WordPress site with WordFence. Primitive attacks are blocked well. As soon as the vulnerability is a bit more complex, WordFence fails. Relying solely on WordFence - especially for a company - is quite risky. In my daily work I encounter cases where someone convinced the responsible parties that WordFence is a silver bullet, and then they bitterly realize that it is not.
Additionally, I showed one (!) method here to trick WordFence’s scanner. I did this because many think WordFence’s scan finds all backdoors and malware and that they are then secure. There are increasingly many people offering these services without really knowing what’s possible. The result is clients who are surprised to be continuously hacked again, even though their site is supposedly safe.
I did not examine WordFence’s smaller competitors. The same generally applies to them. WordFence was chosen because it’s the best-known plugin in this area.
You’re just self-promoting
Yes! If you’ve been hacked, you can hire me. I help by removing the attack and providing preventive measures. So far none of my clients have been hacked again. It’s important to learn from mistakes and avoid repeating them. That can be inconvenient, but it’s necessary. Security doesn’t come at the push of a button - and certainly not from a PHP plugin alone.
I especially enjoy finding vulnerabilities; you can hire me for that too.
To the techies
This article is aimed at laypeople, so overly technical details were omitted. If you’re interested in the demo plugin, feel free to contact me. With it you can test for yourself what “firewalls” allow and what they don’t.
Test system:
- Nginx 1.10 with PHP 7 and MySQL 5.7
- WordPress 4.7.3
- WordFence 6.3.4
- Live site on a NetCups server
Ninja Firewall
After being asked I ran the same attacks against Ninja Firewall and found that it blocked the attacks across all the mentioned vectors. The only exception was PHP Object Injections. However, there is a setting to block serialized strings. In addition to that setting there are many others more suitable for professionals. In other words - you need to know what you’re doing, and if you enable everything you should thoroughly test the system. WordPress makes heavy use of serialized strings - so you might be "secure" but break the site.
If you ask for a recommendation, I would clearly recommend "Ninja Firewall." You’ll get more out of it. Basically the same caveats apply as with WordFence. For many scenarios the plugin offers very good protection. For some specific attacks you’ll be disappointed. For example, the plugin checks $_SERVER, but not every variable (only the most common ones). That’s a place to try and attack. Depending on the type of SQL injection, you aren’t fully protected here either - XSS and SQL injection filters are essentially word filters. If you’re creative and manage to avoid words such as "script" or "FROM", you may slip through. That sounds easy, but in the variety of attack scenarios and vulnerabilities it usually isn’t. Again, the plugin mainly protects what’s inside the WordPress system.
The smallest mistake can quickly render this kind of protection useless. Example: you have several sites - sometimes Drupal, sometimes WordPress, sometimes Piwik. No rights management. WordPress and Drupal are protected by some plugin/firewall, but Piwik isn’t. Piwik gets hacked and a shell disables all security plugins on all sites and hides very well. You’ve lost. That’s why I so often preach that you need a good host with proper user and file permissions!
What I liked a lot was that Ninja Firewall was able to classify the changes inside the binary file. The malware scanner triggered (but rather unreliably - you may need to run it several times). The general change was also detected.
Summary: Use Ninja Firewall and configure it properly - you’ll get more value!