← All security check guides

Is a WordPress site's XML-RPC endpoint open?

xmlrpc.php is the remote-control interface WordPress shipped with long before the REST API existed. It is still enabled by default on most installs, it answers anyone who asks, and it has two properties that make it the first thing an automated attack tries: many authentication attempts fit inside one request, and one of its methods makes the server fetch a URL that the caller chooses.

What an open endpoint costs

The first cost is that password guessing gets cheap. A normal login form takes one request per attempt, which is what rate limiting is built to count. XML-RPC accepts a batch: the system.multicall method packs many authentication attempts into a single request, so a rate limit counting requests barely registers an attack that is trying hundreds of passwords. This is why installs with a strong password on the front door still show up in breach reports.

The second cost belongs to somebody else. The pingback.ping method exists so one blog can tell another it has been linked to, and it works by making the server fetch a URL the caller supplies. Point enough WordPress sites at one target and the pingbacks become a distributed flood coming from thousands of legitimate servers. The same mechanism reaches inward: a URL naming an internal address makes the server fetch something only it can reach, and report back on what happened.

Neither is a flaw in the sense of a bug to be patched. Both are the feature working as designed, which is why the fix is a setting rather than an update, and why an install that has never been neglected can still have it wide open.

Asked, not exploited

There is an easy version of this check that should not be written. Establishing that pingback works by sending a pingback means making the customer's server fetch a URL, which is the abuse the finding is about; a scanner that proves a vulnerability by performing it has attacked the site it was hired to protect.

CheckWeb sends one request, and it is the XML-RPC call that asks the endpoint to describe itself: system.listMethods takes no arguments, changes nothing and reads none of the site's data. The answer is a list of method names. If pingback.ping is on that list, the report says so and raises the severity, because the list is the endpoint's own statement of what it will do. No method on it is ever called.

That answer also does the false-positive work. A great many sites reply 200 to any address at all, so a status code proves nothing here: what proves an XML-RPC server is live is an XML-RPC response document with a method list in it. A catch-all page, a security plugin's block page and a WAF challenge are all rejected, and so is a methodResponse that carries a fault instead of a list, because that is usually a hardening plugin doing its job.

How it looks in the report

The finding names the endpoint, the number of methods it advertised and whether pingback.ping is among them. It sits at medium when the endpoint is simply open, and rises to high when the pingback method is offered, because at that point the site can be pointed at a third party.

The request that produced it is stated in the finding, which matters more here than on most checks: this is the one place the deep scan sends anything other than a plain page fetch, and an owner reading a report is entitled to know exactly what arrived at their server.

It runs only where the site is recognised as WordPress, and only after domain ownership is verified. The free passive scan does not touch this endpoint at all.

Example

WordPress XML-RPC is enabled

xmlrpc.php is answering and it offers pingback.ping. Password guessing gets cheap, because many attempts fit in one request, and the pingback method makes this server fetch a URL somebody else chooses. Turn XML-RPC off unless the mobile apps or Jetpack still need it.

FAIL

POST /xmlrpc.php (system.listMethods) → HTTP 200, methodResponse listing 42 methods, including pingback.ping

Open vs closed

Open

A default install nobody changed. The endpoint answers every visitor, advertises the full method list including the pingback family, and appears in the access log a few hundred times a day from addresses nobody recognises. Nothing is broken and nothing shows on the site, which is why it stays that way for years.

Closed

The path is blocked at the web server or the CDN, or a plugin has switched the endpoint off, and the request never reaches PHP. Where the mobile app or Jetpack is genuinely in use, the endpoint stays but the pingback methods are removed and the path is rate-limited, which keeps the feature and drops both abuses.

Blocking at the edge is worth preferring over a plugin: it costs no PHP execution, so the requests stop consuming the server rather than being turned away by it.

How to turn it off

  • Decide first whether anything still uses it. The WordPress mobile apps and Jetpack do; almost nothing else written in the last decade does, because the REST API replaced it. If neither is in use, the endpoint can be closed outright.
  • Block /xmlrpc.php at the web server or CDN. In Nginx a location block returning 403, in Apache a Files directive denying access, in Cloudflare a firewall rule on the path. The request is then refused before WordPress starts, which is the cheapest possible answer.
  • Or switch it off in WordPress, with a security plugin or by returning false from the xmlrpc_enabled filter. This runs later than an edge rule but survives a change of host, and it is the option that does not require server access.
  • If the endpoint has to stay, remove the pingback methods and rate-limit the path. Unsetting pingback.ping and pingback.extensions.getPingbacks from the xmlrpc_methods filter keeps the app integration working and closes the half that reaches other people's servers.
  • Then check the account names while the subject is open. XML-RPC is what makes guessing cheap; a published login is what tells an attacker which account to guess at, and the two are almost always found together. (WordPress user enumeration covers that half.)
  • Re-run the audit afterwards. Only a request from outside the network shows what the endpoint is currently telling the world, and a rule that was added to the wrong virtual host looks identical to one that works until something checks.

Run a free scan

The free passive scan grades headers, TLS and known CVEs on any site in about thirty seconds, with no signup. Verifying that a domain is owned adds the deep scan, which asks the XML-RPC endpoint to list its own methods and reports what it advertised, without calling any of them.

Check my website

FAQ

Is xmlrpc.php a vulnerability?
No. It is a feature that is enabled by default and that two kinds of abuse happen to fit through. That is why the fix is a setting rather than an update, and why keeping WordPress current does not close it.
Will disabling it break anything?
The WordPress mobile apps and Jetpack use it, and both will stop working. Pingbacks and trackbacks stop as well, which most sites disabled years ago as spam. Nothing else in a modern install depends on it, because the REST API took over the same job.
Does the scan try any of the methods it finds?
Never. One request is sent, and it is the call that asks the endpoint to describe itself. Whether pingback.ping is offered is read from the list that comes back, because calling it would mean making the server fetch a URL, which is the exact abuse the finding warns about.
The endpoint returns 403 already. Is that enough?
Yes, and that is what a closed endpoint looks like from outside. The check reports nothing unless a real XML-RPC document comes back with a method list in it, so a block page, a challenge or a refusal all read as closed.

Related checks