WordPress xmlrpc.php In 2026: Leave It On Or Turn It Off?.
A stock install exposes 80 XML-RPC methods including pingback.ping. Three of four production sites block it and one large one does not.
Short answer: block wordpress xmlrpc on most agency sites, after checking that nothing on the site actually uses it. It is not a vulnerability, and the panic around it is overdone, but it is an authentication surface with genuinely useful attack ergonomics and almost no remaining legitimate use.
What it exposes when it answers

system.multicall is the one that matters: itbatches many calls into a single HTTP request, so an attacker can attempt many password guesses inside one request and defeat rate limiting that counts requests rather than attempts.*
That combination, system.multicall wrapping repeated wp.getUsersBlogs calls, is why XML-RPC has the reputation it has. Pair it with usernames enumerated from the REST API and the guesswork is gone.
pingback.ping is the other one. It has been used to make WordPress sites into reflectors for traffic aimed at somebody else, which turns your client’s server into a participant in an attack rather than the target of one.
Watching multicall actually batch three calls into one request
The system.multicall mechanism is described in the abstract everywhere XML-RPC’s brute-force ergonomics get discussed, so I sent a real multicall request, using only the harmless demo.sayHello test method, to see the batching happen rather than take the description on faith.
curl -s -X POST -H 'Content-Type: text/xml' -d '<?xml version="1.0"?>
<methodCall>
<methodName>system.multicall</methodName>
<params><param><value><array><data>
<value><struct><member><name>methodName</name><value><string>demo.sayHello</string></value></member>...</struct></value>
<value><struct>... (repeated three times) ...</struct></value>
</data></array></value></param></params>
</methodCall>' https://woocommerce.com/xmlrpc.php
<array><data>
<value><array><data><value><string>Hello!</string></value></data></array></value>
<value><array><data><value><string>Hello!</string></value></data></array></value>
<value><array><data><value><string>Hello!</string></value></data></array></value>
</data></array>
One HTTP request, three method calls, three independent results back in a single response. I deliberately used a harmless demo method rather than anything touching authentication, but the mechanism demonstrated is exactly the one this post’s opening section describes in the abstract: a single POST to xmlrpc.php can carry an arbitrary number of independent method calls, each evaluated separately, each producing its own result in the same response. Swap demo.sayHello for a login attempt inside that same structure and the arithmetic that makes XML-RPC a more efficient brute-force surface than the ordinary login form becomes concrete rather than theoretical: a rate limiter counting HTTP requests sees one request where a password-guessing script attempted many.
What real sites do

state of this question. It is a decision with trade-offs, not a setting with one correct value.*
| Site | xmlrpc.php | Reading |
|---|---|---|
| theplusaddons.com | 403 | blocked, most likely at the CDN |
| nexterwp.com | 403 | blocked |
| uichemy.com | 403 | blocked |
| woocommerce.com | 200 | answering, a legitimate choice, not a mistake |
| stock WordPress install | 200 | 80 methods returned, including pingback.ping |
Caveat: four production sites, one small sample. This is not a claim about what share of WordPress sites block XML-RPC generally. It shows a real split among sites I could verify directly, which is enough to make the point that “block it” is not universal practice even among well-run sites.
I include woocommerce.com deliberately. If leaving XML-RPC enabled were straightforwardly negligent, sites of that size and scrutiny would not do it. They have rate limiting and a security team; the calculation is different from a small agency site with neither.
What woocommerce.com actually left enabled, checked method by method
Reading the earlier table, “woocommerce.com answers, 200,” could reasonably be taken to mean it exposes the full stock method list, pingback.ping included. I pulled the actual method list to check rather than let that reading stand unverified.
curl -s -X POST -H 'Content-Type: text/xml' \
-d '<?xml version="1.0"?><methodCall><methodName>system.listMethods</methodName></methodCall>' \
https://woocommerce.com/xmlrpc.php
79 methods came back, one fewer than the 80 a stock install exposes. I diffed the full list against a second real, live site, wordpress.org, which also answers 200 and returns 79 methods of its own:
< demo.addTwoNumbers (present on woocommerce.com, absent from wordpress.org)
> pingback.ping (present on wordpress.org, absent from woocommerce.com)
Every other method, wp.getUsersBlogs, system.multicall, the full metaWeblog and mt.* publishing surface, matches exactly between the two. The single difference is pingback.ping, present on wordpress.org and specifically removed from woocommerce.com, replaced in the listing by a harmless demo method rather than simply vanishing.
That is not “XML-RPC left wide open on a major store.” It is the exact surgical middle path this post already recommends as an alternative to blocking the whole endpoint: leave the publishing methods available, in case something legitimate still calls them, and remove specifically the one method with a documented history of turning a site into a reflector for traffic aimed at someone else. wp.getUsersBlogs, the method that makes system.multicall brute-forcing effective, is still present on both sites, which means neither of them has closed the credential-stuffing ergonomics this post opens with. They have made a considered, narrower decision about the reflection risk specifically, and left the rest of the surface as a trade-off against whatever legacy tooling still calls it. Checking the actual method list, rather than reading a 200 as “everything is exposed,” is the difference between describing that decision accurately and flattening it into a single yes-or-no reading of a status code.
Deciding for a client site

where it does break will be a client’s, and the symptom is a publishing workflow failing quietly rather than an error anybody sees.*
| Depends on XML-RPC? | Still? | Notes |
|---|---|---|
| Jetpack, older versions | sometimes | modern Jetpack largely uses its own connection |
| the WordPress mobile app | no | uses the REST API now |
| desktop blog editors | yes | older clients speak XML-RPC only, rare, worth asking |
| trackbacks and pingbacks | yes | almost nobody wants these in 2026 |
| some backup/migration plugins | sometimes | check the specific plugin before blocking live |
| everything else | no | the REST API replaced it for practically all modern tooling |
My default is to block it, for one reason: the remaining legitimate uses are rare and easy to identify, while the surface it presents is permanent and needs no vulnerability to be useful.
If you would rather not block it outright, disabling pingback.ping alone removes the reflection problem while leaving publishing methods intact.
Blocking WordPress xmlrpc.php properly
At the web server or CDN, so the request never reaches PHP:
location = /xmlrpc.php { deny all; }
<Files "xmlrpc.php">
Require all denied
</Files>
A PHP-level filter still boots WordPress on every request, which means an attacker can still consume your client’s resources by hammering it. Blocking above WordPress is both safer and cheaper.
Then verify, because a rule you did not check is not a rule:
curl -s -o /dev/null -w '%{http_code}\n' -X POST \
-H 'Content-Type: text/xml' \
-d '<?xml version="1.0"?><methodCall><methodName>system.listMethods</methodName></methodCall>' \
https://example.com/xmlrpc.php
403 or 404 is what you want. 405 on a GET means nothing, because XML-RPC only answers POST. That is a real trap: testing with a browser gives you 405 and the false impression it is closed.
I confirmed the trap directly, checking both request methods against every site in this post’s tables:
curl -s -o /dev/null -w '%{http_code}\n' -X POST -H 'Content-Type: text/xml' \
-d '<?xml version="1.0"?><methodCall><methodName>system.listMethods</methodName></methodCall>' \
https://example.com/xmlrpc.php
curl -s -o /dev/null -w '%{http_code}\n' https://example.com/xmlrpc.php
| Site | POST | GET |
|---|---|---|
| theplusaddons.com | 403 | 403 |
| nexterwp.com | 403 | 403 |
| woocommerce.com | 200 | 405 |
| wordpress.org | 200 | 405 |
The two blocked sites return the same code either way, 403, because the block happens above WordPress entirely and refuses every method regardless. The two sites that leave XML-RPC answering both return 405 on a plain GET, which is exactly the false-negative this post warns about: opening either of those URLs in a browser, the most natural first thing to try, produces a 405 Method Not Allowed that reads as “blocked” to anyone who has not specifically learned to distrust it. Both of those sites are, per the tables in this post, deliberately leaving XML-RPC open. A 405 observed casually would report the opposite of the truth on either one. wordpress.org is a second real, live confirmation of the same pattern this post’s original table found on woocommerce.com alone, which is worth having before generalising “well-run sites sometimes leave this on” from a sample of one.
Where it fits
XML-RPC is worth twenty minutes per portfolio, once, and then it stays fixed. That makes it unusual on this blog, where most checks drift and need repeating.
What does drift is whether a CDN rule survives a migration, which is the same reason cache exclusions get lost when a site moves. Re-run the curl after any hosting or CDN change, in the same pass where you confirm the security headers survived the move.
Protuno’s free audit reports whether xmlrpc.php answers, from the domain alone, alongside the other exposure checks. Straight with you as on every post here: Rook, the Security agent that would re-check this after each migration, is built and named but not live yet.
Test the site you moved most recently. That is where the rule went missing.
What the method-diff approach adds to a portfolio audit
The system.listMethods comparison run against woocommerce.com and wordpress.org earlier in this post is worth building into a recurring check rather than treating as a one-off curiosity, because it answers a more useful question than a bare status code can.
A status-code-only audit across a portfolio produces exactly two buckets: blocked and not blocked. That is enough to flag the sites worth a closer look, but it cannot distinguish a site that deliberately left the full stock surface open, the higher-risk case, from one that has already made the narrower pingback.ping-only trim woocommerce.com has. Two sites answering 200 can be in meaningfully different risk postures, and a scan that stops at the status code reports them identically.
curl -s -X POST -H 'Content-Type: text/xml' \
-d '<?xml version="1.0"?><methodCall><methodName>system.listMethods</methodName></methodCall>' \
"https://$SITE/xmlrpc.php" | grep -o 'pingback\.ping\|wp\.getUsersBlogs'
Running that against every site in a portfolio that answers 200 on the basic probe adds one more request per site and turns “XML-RPC is open” into a specific, actionable finding: which of the two methods that actually matter, the reflection vector and the enumeration target system.multicall needs to make brute-forcing effective, are present. A site missing pingback.ping specifically has already had the conversation this post is trying to start. One still serving it has not, regardless of how the initial status-code scan reported it.
The honest cost-benefit, restated after testing both sides
Having now tested the block, the leave-open case, and the surgical middle path directly rather than describing all three secondhand, the actual trade-off is narrower than “vulnerability, fix it” framing usually presents it. Blocking costs nothing on the overwhelming majority of agency sites, because the legitimate remaining uses named earlier in this post are genuinely rare and easy to confirm absent with one conversation. Leaving it open, the way two real, well-resourced sites checked in this post do, is not negligence when it is a deliberate choice backed by rate limiting and monitoring neither of those two sites lacks. The middle path, disabling pingback.ping alone, is not a compromise position invented for this post. It is what at least one of those two sites has already implemented, verified here by diffing its actual method list against a comparable site that has not.
The wrong response to any of this is treating the presence of XML-RPC on a 200 response as automatically alarming, the same instinct this blog argues against for every other single signal in isolation. The right one is the same three-line check this post has now demonstrated twice: request the method list, read what is actually there, and decide based on the specific methods exposed rather than the bare fact that something answered.
The attack this post’s method-list check is guarding against
A walkthrough of how the system.multicall method specifically gets used to amplify a brute-force attack, the exact method name worth checking for in the list rather than blocking the file outright.
Comments