The fix, in one snippet
location = /xmlrpc.php { deny all; return 404; }
Illustrative values. Change the paths, hostnames and options to match your own site before using it.
The sections below explain what is tested, why it matters and the alternatives.
What we test
Scan.now sends a single GET /xmlrpc.php. An enabled endpoint answers with HTTP 405 and the body "XML-RPC server accepts POST requests only."; a 403 or 404 means it has been disabled or blocked, and the check passes. Scan.now also looks for an X-Pingback response header on the homepage, which WordPress adds to advertise the endpoint. No POST request, no method call and no authentication attempt is made. Rated medium: the endpoint is not a vulnerability on its own, but it is a second authentication surface with weaker protections than wp-login.php, and it is the usual vehicle for the brute-force and amplification abuse described below. It is checked only when WordPress is detected; see also wordpress-user-enumeration, which supplies the usernames that make brute force practical.
Why it matters
XML-RPC predates the REST API and was how mobile apps and desktop clients published to WordPress. Three properties make it a liability today. First, the system.multicall method lets one HTTP request carry hundreds of wp.getUsersBlogs calls, each with a different password, so an attacker can test thousands of credentials per minute while login-rate-limiting plugins that only watch wp-login.php see nothing. Second, most two-factor plugins hook the normal login form and not XML-RPC, so a 2FA-protected account can still be brute-forced here. Third, the pingback.ping method makes your server fetch an arbitrary URL, which has been used to turn fleets of WordPress sites into a distributed denial-of-service amplifier against third parties, and to probe internal networks. Jetpack and a few remote-publishing clients still use the endpoint; most sites do not need it. The WordPress scanning guide ranks this among the first things to close.
How to fix it
If nothing you use depends on it, block the file at the web server, which is more complete than the WordPress filter. nginx:
location = /xmlrpc.php {
deny all;
return 403;
}
Apache (vhost or .htaccess):
<Files "xmlrpc.php">
Require all denied
</Files>
Cloudflare WAF custom rule: expression (http.request.uri.path eq "/xmlrpc.php"), action Block; add an exception for Jetpack's published IP ranges if you rely on it. If you must keep the endpoint for one client, disable the dangerous methods and remove the advertisement instead:
add_filter('xmlrpc_enabled', '__return_false'); // disables authenticated methods
add_filter('xmlrpc_methods', function ($methods) {
unset($methods['pingback.ping'], $methods['system.multicall']);
return $methods;
});
add_filter('wp_headers', function ($headers) { unset($headers['X-Pingback']); return $headers; });
Note that xmlrpc_enabled only turns off methods that require authentication; the file still responds, which is why the server-level block is preferred. Whichever route you take, also enforce strong passwords and a login limiter, because wp-login.php remains.
Where this fits
WordPress xmlrpc.php enabled is check 8 of 14 that the website vulnerability scanner runs under exposed files and information disclosure, ordered the way they are worth fixing. That ordering is the point: Fixing this one while the check above it still fails buys less than it looks like.
Fix this one first
Above it in the same category sits WordPress user enumeration via REST API (medium), where the WordPress REST API or author archives reveal account usernames to anonymous visitors, giving attackers half of each credential pair before they start guessing passwords. An attacker who has that does not need this, so it is the better use of the same hour.
What fixing this still leaves open
WordPress xmlrpc.php enabled closes one route in. Immediately below it: Exposed .DS_Store file, where a macOS .DS_Store file is served from the web root; HTTP TRACE method enabled, where the server answers HTTP TRACE requests by echoing them back; WordPress version disclosure, where the site runs WordPress and reveals its exact core version through the generator tag, asset query strings, readme.html or the feed, letting attackers match it against known core vulnerabilities.
Found in the same scan
The website vulnerability scanner reports this alongside checks from other categories that are at least as serious, including Certificate chain and hostname validation, where the certificate presented for this hostname did not validate: The chain does not reach a trusted root, an intermediate is missing, the name does not match, or the certificate is self-signed or expired, and HTTPS is available, where the site could not be reached over HTTPS on port 443, or the TLS handshake failed. A single run of website vulnerability scanner answers all of them at once.
The first few lines
You are a senior web engineer. I ran a security and SEO scanner against my site and it reported the finding below. Fix it properly rather than suppressing the symptom.
Finding: WordPress xmlrpc.php enabled (medium severity)
Scanner check id: wordpress-xmlrpc
The rest of this prompt names the pages and line numbers we found the problem on, the configuration to change, and the constraints a good answer has to respect. It is free, it just needs an account so the work is not scraped wholesale.
Sign in with GoogleSigning in is free and takes one click. We store your email address and nothing else.