Blocking access to the WordPress users sitemap through Nginx (via .conf or with Puppet)

You can easily slow down attackers by blocking access to wp-sitemap-users-1.xml in Nginx.

WordPress publishes a list of users at https://<domain>/wp-sitemap-users-1.xml. For small blogs this exposes the admin account username, which can simplify brute force attacks. For large blogs incorporating SCIM technology, it exposes your entire directory to the Internet.

The advantage of doing this at Nginx-level (rather than within WordPress’ PHP code) is that it’ll survive WordPress upgrades.

Blocking via Nginx .conf

Add the below to your site’s .conf file.

location ~ wp-sitemap-users-1.xml$ {
  deny all;
  index     index.html index.htm index.php;
}

Blocking via Puppet

Prerequisite is you’re using the Vox Pupuli module.

nginx::resource::location { "${name}_wp-sitemap-users-1_xml":
  ensure        => present,
  server        => $name,
  location      => '~ wp-sitemap-users-1.xml$',
  location_deny => ['all']
}

The $name variable should correspond to a nginx::resource::server definition. For example, here’s the full config this blog uses in Puppet. web.pp defines an nginx_php_server and site.pp simply invokes it if it should be applied to a node.

web.pp

$full_web_path = '/var/www'
$fastcgi_pass = 'unix:/var/opt/remi/php82/run/php-fpm/www.sock'

# Configure an Nginx server with PHP
define web::nginx_php_server (
  $php                  = true,
  $wordpress            = false,
  $www_root             = "${::full_web_path}/${name}/public_html",
  $location_cfg_append  = undef,
) {
  nginx::resource::server { $name:
    ensure               => present,
    use_default_location => false, # https://github.com/voxpupuli/puppet-nginx/issues/639
    listen_port          => 80,
    www_root             => $www_root,
    owner                => 'nginx',
    group                => 'nginx',
    mode                 => '0755',
    access_log           => "/var/log/nginx/${name}_access.log",
    error_log            => "/var/log/nginx/${name}_error.log",

    location_cfg_append  => {
      try_files => '$uri $uri/ =404'
    },
    index_files          => [ 'index.php' ],
  }

  if $php {
    nginx::resource::location { "${name}_root":
      ensure    => present,
      server    => $name,
      location  => '/',
      try_files => ['$uri', '$uri/', '/index.php?q=$uri&$args'],
    }
    nginx::resource::location { $name:
      ensure              => present,
      server              => $name,
      location            => '~ \.php$',
      index_files         => ['index.php', 'index.html', 'index.htm'],
      proxy               => undef,
      fastcgi             => $::fastcgi_pass,
      fastcgi_script      => undef,
      location_cfg_append => {
        fastcgi_split_path_info => '^(.+\.php)(/.+)$',
        fastcgi_index           => 'index.php',
        fastcgi_connect_timeout => '3m',
        fastcgi_read_timeout    => '3m',
        fastcgi_send_timeout    => '3m'
      }
    }
  }

  if $wordpress {
    # block access to users sitemap, e.g. https://blog.abctaylor.com/wp-sitemap-users-1.xml
    nginx::resource::location { "${name}_wp-sitemap-users-1_xml":
      ensure        => present,
      server        => $name,
      location      => '~ wp-sitemap-users-1.xml$',
      location_deny => ['all']
    }
  }
}

site.pp

... omitted for brevity

web::nginx_php_server { "blog.abctaylor.com":
  wordpress => true,
}

... omitted for brevity

Test

https://blog.abctaylor.com/wp-sitemap-users-1.xml returns error 403.

Let’s see if Google was able to index my user list. Looking at the sitemap I submitted (https://blog.abctaylor.com/wp-sitemap.xml) in Search Console, it pulls all the sitemaps listed at the top level, but not the user list.