XML-RPC, REST, and the WordPress surfaces still leaking attack surface.

Two WordPress endpoints exist on every site by default. Both are routinely used in attacks. Most operators don't realize.

WordPress ships with two API surfaces enabled by default on every install: XML-RPC and the REST API. Both predate the use cases most sites have today. Both are routinely used in brute-force, enumeration, and DoS attacks. Most operators have no idea they're exposed, because the endpoints don't appear in any admin UI. Here's what's still exposed by default, and how to lock down what you don't use.

Every WordPress install ships with two API surfaces enabled by default. /xmlrpc.php has existed since the late 2000s, originally for desktop blogging clients that nobody uses anymore. /wp-json/ is the modern REST API, added in WordPress 4.7 (2016). Both endpoints respond on every WordPress site in the world, regardless of whether the site uses them. Both are routinely scanned and abused. Most site operators don’t realize they’re exposed because neither shows up in any admin UI.

XML-RPC: legacy with active attack value.

XML-RPC was originally how WordPress talked to external blog editors (Windows Live Writer, MarsEdit, Ecto). It was also the path for Jetpack to talk to WordPress.com. Jetpack actually still relies on XML-RPC as its primary connection protocol today, though external desktop editors mostly stopped existing.

It’s still on every WordPress site, and it’s actively used for:

  • Brute-force login. The wp.getUsersBlogs XML-RPC method accepts a username and password. It does this without the rate limits and lockouts that /wp-login.php sometimes has, and it accepts multiple authentication attempts per request via system.multicall. An attacker can try thousands of password combinations per HTTP request. That’s catastrophic for any account using a weak password.
  • DDoS pingback amplification. The pingback.ping method causes the target WordPress site to make an HTTP request to an arbitrary URL. Attackers point thousands of WordPress sites at a single victim and use them as an amplifier. Your site doesn’t get attacked; it becomes part of the attack.
  • User enumeration. Even when authentication fails, some XML-RPC methods leak information about whether a username exists. Attackers harvest valid usernames before targeting passwords.

If nothing on your site uses XML-RPC — and almost certainly nothing does — the right answer is to turn it off entirely. One filter:

add_filter('xmlrpc_enabled', '__return_false');

For belt-and-suspenders, also block requests to /xmlrpc.php at the WAF or server level so the file never gets executed. Cloudflare has a managed rule for this; most hosts can add a deny rule for the path.

The REST API: useful, also exposed.

The REST API at /wp-json/ is genuinely useful — Gutenberg uses it, mobile apps use it, headless setups depend on it. But most marketing sites use only a tiny fraction of its surface, and the rest is exposed to anonymous requests by default. Things to know:

  • User enumeration via /wp-json/wp/v2/users. By default, this returns a list of all users who have actually published at least one public post — usernames, display names, sometimes more. Attackers use this to harvest valid login names. Most sites don’t need it exposed to the public. Restrict it with a filter that checks current_user_can('list_users').
  • Post enumeration via /wp-json/wp/v2/posts. Returns all published posts in a structured form. This is sometimes desired (a headless front-end depends on it), but for a traditional WordPress site rendering its own HTML, exposing the full post list as JSON is unnecessary and gives attackers a structured map of the site’s content.
  • Search via /wp-json/wp/v2/search. Same as posts — useful for some sites, unnecessary for most. Rate-limit at minimum.
  • Application Passwords. WordPress 5.6+ ships with the ability to generate application-specific passwords. Useful for authenticated API access, but each one is a credential. Disable if not in use; audit if it is.

What “lock down” actually looks like.

The right posture isn’t “block the REST API entirely” (you’d break Gutenberg). It’s “restrict the endpoints you don’t need.” A reasonable baseline for a typical marketing site:

  • Disable XML-RPC entirely (filter + WAF rule) — unless you use Jetpack, in which case restrict it at the WAF level to Automattic’s IPs only.
  • Require authentication on the users endpoint
  • Rate-limit the posts and search endpoints if they’re not in use, or restrict to authenticated requests
  • Disable Application Passwords if not in use (a single filter)
  • Add rate limiting at the WAF for all /wp-json/ traffic regardless of endpoint — reasonable thresholds protect against scraping and enumeration even on endpoints you can’t fully lock down

How to know what you actually use.

Before turning anything off, audit. Log all requests to /xmlrpc.php and /wp-json/* for a week. If /xmlrpc.php sees nothing but scanner traffic (it will), disabling is safe. If /wp-json/wp/v2/users is only ever requested by your own admin, restricting it is safe. If /wp-json/wp/v2/posts is being called by a mobile app or external integration, you’ll know before you break it.

The general principle is the same as every other surface: don’t leave attack-surface enabled by default just because you haven’t gotten around to turning it off. Disabling the parts you don’t use is one of the cheapest security wins on a typical WordPress site. See security hardening for the rest of the baseline.

Let's talk about what you're building

No proposals. No pitch decks. Just a conversation about your project and whether I'm the right fit to build it.

Start a Conversation