Blocklist bypass through user agent spoofing – (Blackhole for Bad Bots <= 3.3.3)

Affected pluginBlackhole for Bad Bots
Active installs30,000+
Vulnerable version<= 3.3.3
Audited version3.3.3
Fully patched versionPENDING
Recommended remediationPENDING


A malicious bot spoofing his User-Agent header to one in the plugin’s allowlist can bypass the plugin’s full functionality.

Proof of concept

The HTTP_USER_AGENT header can not be trusted as an attacker / malicious bot can set it to arbitrary values.

The plugin uses the User-Agent header to decide if the current request should be exempt from offenses.

function blackhole_whitelist($vars) {
   global $bbb_options;
   list ($ip_address, $request_uri, $remote_host, $query_string, $user_agent, $referrer, $protocol, $method) = $vars;
   // bots
   $whitelist_bots = isset($bbb_options['bot_whitelist']) ? $bbb_options['bot_whitelist'] : '';
   $whitelist_bots = array_filter(array_map('trim', explode(',', $whitelist_bots)));
   if (!empty($whitelist_bots)) {
      foreach ($whitelist_bots as $bot) {
         if (stripos($user_agent, $bot) !== false) {
            return true;
   // ips
   $whitelist_ips = isset($bbb_options['ip_whitelist']) ? $bbb_options['ip_whitelist'] : '';
   $whitelist_ips = array_filter(array_map('trim', explode(',', $whitelist_ips)));
   foreach ($whitelist_ips as $ip) {
      if (strpos($ip, '/') === false) {
         if (substr($ip_address, 0, strlen($ip)) === $ip) {
            return true;
      } else {
         if (blackhole_ip_in_range($ip_address, $ip)) {
            return true;
   return false;

The User-Agent is determined in the blackhole_get_vars function.

$user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field($_SERVER['HTTP_USER_AGENT']) : '';

The $user_agent variable is assigned directly from the untrusted HTTP header. Consequently, any bot that spoofs its User-Agent can bypass the plugin’s functionality.

curl -X GET https://local.test?blackhole=1 -H "User-Agent: google"

Proposed patch

Use PHP’s gethostbyaddr and gethostbyname functions to perform reverse DNS lookups if the value of the User-Agent header is in the allowlist.



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


Leave a Reply

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