# xmlrpc.php in WordPress: what it is, how it is attacked and how to disable it safely

> xmlrpc.php is the old remote API of WordPress. Bots use it to guess passwords and to turn your site into a pingback cannon. Check whether anything still needs it, then block it at the right level.

Updated 2026-09-26 · WordPress & WooCommerce · HTML version: https://getreport.app/guides/xmlrpc-php

`xmlrpc.php` is the file in the root of every WordPress site that answers XML-RPC, the remote API WordPress used before the REST API existed. It lets an app log in, publish posts and send pingbacks over HTTP. Very few sites still need it, while bots use it every day to guess passwords and to send pingback requests to other sites. This guide explains what the file does, how it is attacked, how to check whether anything on your site still depends on it, and how to disable XML-RPC in WordPress at the level that fits your setup. It is part of the [WordPress security checklist](https://getreport.app/guides/wordpress-security-basics-without-a-plugin), where XML-RPC is step 6.

## Quick answer

- **You can't delete `xmlrpc.php`.** It is a core file and the next update puts it back. Block it or switch it off instead.
- **Check what uses it first:** Jetpack's connection, some mobile and desktop publishing apps, and a few remote-management and publishing services.
- **Nothing uses it?** Block the file at the server or CDN so requests never reach PHP. That stops both login guessing and pingbacks.
- **Something uses it?** Keep it open and rate-limit `POST /xmlrpc.php` at your CDN or server instead.
- **The `xmlrpc_enabled` filter is a half measure.** It switches off methods that need a login, but pingbacks still work.
- **Verify with `curl`:** a blocked file answers 403 (or 404) to a POST.

## What is xmlrpc.php?

XML-RPC is a protocol from the late 1990s: a client sends an XML document over HTTP naming a method and its arguments, and the server sends back an XML answer. WordPress implemented it so that desktop editors, the first mobile apps and other blogs could talk to a site. Methods such as `wp.newPost`, `wp.getUsersBlogs` and `pingback.ping` all go through one address, `https://example.com/xmlrpc.php`.

WordPress still ships and enables it for backwards compatibility. The REST API, under `/wp-json/`, has replaced it for the block editor and for almost every modern plugin and app. Since WordPress 5.6, application passwords (Users → Profile → Application Passwords) let apps authenticate to the REST API without your main password.

Your site advertises the endpoint in two places: a `<link rel="EditURI">` tag in the page head pointing to `xmlrpc.php?rsd`, and an `X-Pingback` header on single posts that accept pings. That is how bots find it, although most simply try the address on every site they see.

## How attackers use xmlrpc.php

### Password guessing

`wp.getUsersBlogs` and other authenticated methods take a username and password in the request body. That gives brute-force scripts a second login form, one without the cookies, redirects and nonces of `wp-login.php`, so it is simpler to automate. Login-limiting features that only watch `wp-login.php` miss these attempts.

XML-RPC also has `system.multicall`, which runs many methods in one request. Until WordPress 4.4 a script could pack hundreds of password guesses into a single HTTP request. Since 4.4, all further login attempts inside a multicall fail after the first failed one, so the amplification no longer works. Plain one-guess-per-request attacks still do, and they are cheap.

### Pingback abuse

`pingback.ping` asks your site to fetch another URL to verify a link. Attackers send thousands of these requests to thousands of WordPress sites, all naming the same victim, and the sites dutifully fetch the victim's page: a distributed denial-of-service attack with your server as one of the senders. The same method can be used to make your server request internal addresses or to reveal its real IP behind a CDN. It needs no login, which is why the `xmlrpc_enabled` filter does not stop it.

### Load

Even failed requests start PHP and load WordPress. On shared hosting, a steady stream of `POST /xmlrpc.php` can use enough CPU to slow the whole site. If your access log shows hundreds of these a day and you do not use XML-RPC, that is capacity spent on bots.

## Does anything on your site still need XML-RPC?

Check before you block it. Things that commonly use it:

- **Jetpack.** Its connection to WordPress.com uses XML-RPC. Blocking the file breaks Jetpack's features, from stats to backups. If you run Jetpack, rate-limit instead of blocking.
- **Mobile and desktop publishing apps.** Older versions of apps that post to self-hosted WordPress, and some desktop blog editors, log in through XML-RPC. Current apps increasingly use the REST API with an application password; check the app's own documentation.
- **Remote management and publishing services.** Some site-management dashboards, cross-posting tools and older integrations call XML-RPC. Check the settings of anything that logs in to your site from outside.
- **Pingbacks and trackbacks.** If you want other blogs' pingbacks to appear as comments, XML-RPC must stay on. Most sites turn pingbacks off anyway under Settings → Discussion.

The quickest way to know is your access log. Search it for `xmlrpc.php` and look at where the requests come from:

```bash
# Requests to xmlrpc.php in the last log, grouped by client IP
grep "xmlrpc.php" /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head
```

Requests from your own office, Jetpack's servers or a service you use are legitimate. Requests from hundreds of unrelated addresses, all `POST`, are bots.

## How to disable XML-RPC in WordPress

There are three levels, from most to least effective. Use one.

### 1. Block the file at the server

This stops every XML-RPC request before PHP runs, including pingbacks. It is the right choice when nothing on the list above applies.

```nginx
# nginx, inside the server block for the site
location = /xmlrpc.php {
    deny all;
    access_log off;
    log_not_found off;
}
```

```apache
# .htaccess in the WordPress folder (Apache 2.4)
<Files "xmlrpc.php">
    Require all denied
</Files>
```

Reload nginx (`sudo nginx -t && sudo systemctl reload nginx`) after the change. On Apache the `.htaccess` rule applies straight away. If you have to allow one service, nginx can `allow` its addresses above `deny all`; get the list from the service's documentation.

### 2. Block or rate-limit it at the CDN

On Cloudflare, a custom WAF rule does the same job at the edge, so the request never reaches your host. In Security → WAF → Custom rules, create a rule with this expression and the action **Block**:

```text
(http.request.uri.path eq "/xmlrpc.php")
```

If Jetpack or an app needs XML-RPC, use a rate limiting rule on the same path instead, for example more than 5 requests in 1 minute from one IP address leads to a block for 10 minutes. [Rate limiting and bot protection on a small site](https://getreport.app/guides/rate-limiting-and-bot-protection-on-a-small-site) covers the thresholds, and [Cloudflare settings for speed and security](https://getreport.app/guides/cloudflare-settings-for-speed-and-security) the rest of the dashboard.

### 3. Switch it off inside WordPress

When you cannot change the server or CDN, a must-use plugin can turn XML-RPC off from inside WordPress. Requests still reach PHP, so it saves no server capacity, but they are refused. The `xmlrpc_enabled` filter alone only disables methods that need a login; WordPress's own documentation for the filter says it does not control pingbacks. Remove the pingback methods as well:

```php
<?php
// wp-content/mu-plugins/disable-xmlrpc.php
// Refuse every XML-RPC method that needs a login.
add_filter( 'xmlrpc_enabled', '__return_false' );

// Remove the methods that work without a login.
add_filter( 'xmlrpc_methods', function ( $methods ) {
    unset( $methods['pingback.ping'], $methods['pingback.extensions.getPingbacks'] );
    return $methods;
} );

// Stop advertising the pingback endpoint in the X-Pingback header.
add_filter( 'wp_headers', function ( $headers ) {
    unset( $headers['X-Pingback'] );
    return $headers;
} );
```

Files in `wp-content/mu-plugins/` load automatically, cannot be deactivated from the Plugins screen and survive theme changes. Many security plugins have a "Disable XML-RPC" switch that does something similar; check whether it also covers pingbacks.

## How to check that XML-RPC is off

Send a harmless request that lists the available methods:

```bash
curl -s -o /dev/null -w "%{http_code}\n" -X POST \
  -H "Content-Type: text/xml" \
  --data '<?xml version="1.0"?><methodCall><methodName>system.listMethods</methodName></methodCall>' \
  https://example.com/xmlrpc.php
```

- **403 or 404:** the server or CDN blocks the file. XML-RPC is off.
- **200:** the file answers. Drop the `-o /dev/null -w …` part to read the response: with the must-use plugin above, `pingback.ping` is missing from the list, and a method that needs a login returns the fault "XML-RPC services are disabled on this site".
- **405 on a GET:** normal. Visiting `xmlrpc.php` in a browser shows "XML-RPC server accepts POST requests only" whether or not it is protected, so a browser test proves nothing.

Then check that what you rely on still works: Jetpack's connection status under Jetpack → Dashboard, a test post from your app, a pingback if you use them.

## What getReport checks

The [WordPress security scan](https://getreport.app/tools/wordpress-checker) recognises WordPress from the page, including the `xmlrpc.php` link in the head, and checks the public signs attackers combine with XML-RPC: an exposed "admin" login name and an outdated WordPress version.

> **Free tool:** [WordPress security scan and health check](https://getreport.app/tools/wordpress-checker): Free WordPress security scan and health check from the outside: outdated core, closed plugins, exposed files, blocked indexing and classic launch mistakes.

> **Check: No default admin author exposed.** /?author=1 redirects to /author/admin/, which confirms a login name called "admin" exists. Brute-force scripts try that name first.
>
> 1. Create a new administrator with a unique username, log in as it, delete "admin" and attribute its content to the new user.
> 2. Optionally disable author archives or the ?author= redirect in your security plugin.

> **Check: CMS version.** Old CMS versions have published security holes that bots scan for automatically, and the generator tag advertises the exact version to them.
>
> 1. Back up the site, then update the CMS from its admin dashboard; update plugins and themes at the same time.
> 2. Remove the generator tag (WordPress: remove_action('wp_head', 'wp_generator') in functions.php).

A dedicated check for an open `xmlrpc.php` is planned for the WordPress Doctor. It needs to send a POST request, which the report's request guard does not do yet. When it ships, it will show a plain yes or no to anyone who runs the report, and the details only to the site's verified owner, like the other sensitive WordPress checks.

## Common mistakes

- **Deleting `xmlrpc.php`.** The next core update restores it, and until then some plugins may fatal-error. Block it instead.
- **Relying on the `xmlrpc_enabled` filter alone.** Password guessing stops, pingback abuse does not. Add the `xmlrpc_methods` filter, or block the file.
- **Blocking it with Jetpack active.** Jetpack disconnects and its features stop. Rate-limit instead.
- **Installing a plugin just for this.** Two lines of server config or one must-use file do the job without another plugin to update.
- **Protecting XML-RPC but not the login.** The same bots try `wp-login.php`. Rate-limit both and turn on two-factor login, as in [WordPress login security](https://getreport.app/guides/wordpress-login-security).

## Questions people ask

### Should I disable XML-RPC in WordPress?

Yes, unless something uses it. XML-RPC (`/xmlrpc.php`) is an old remote API that attackers use for password guessing and pingback abuse. The block editor and the REST API do not need it; Jetpack and some mobile apps and remote publishing tools do. Block it at the server or CDN, or with a must-use plugin, then check that nothing you rely on stopped working.

### Can I delete xmlrpc.php?

No. It is a WordPress core file, and every core update puts it back, sometimes within hours through automatic updates. Deleting it also triggers integrity warnings in security scanners. Block access to it in nginx, Apache or your CDN instead, which has the same effect for visitors and bots and survives updates.

### Why is xmlrpc.php getting so many requests?

Because bots try it on every WordPress site they find. Most of the `POST /xmlrpc.php` lines in an access log are password guesses or pingback requests from many different addresses. They cost server capacity even when they fail. If you do not use Jetpack or an app that needs XML-RPC, block the file at the server or CDN and the requests stop reaching WordPress.

### Does Jetpack need XML-RPC?

Yes. Jetpack's connection between your site and WordPress.com uses XML-RPC, so blocking `xmlrpc.php` breaks its features. If you run Jetpack, keep the endpoint open and protect it with a rate limit at your CDN or server instead, and make sure every administrator uses two-factor login so guessed passwords are worthless.

### What does "XML-RPC server accepts POST requests only" mean?

It means you opened `xmlrpc.php` in a browser, which sends a GET request, and the file answered that it only takes POST. It is normal and says nothing about whether XML-RPC is protected. Test with a POST request, for example with the `curl` command in this guide: a 403 or 404 means the file is blocked.
