Contents
Overview — Why partially block xmlrpc.php and how this helps
WordPress exposes an XML-RPC endpoint at /xmlrpc.php that implements a set of remote methods (wp., pingback., blogger., system. and others). That endpoint is useful for legitimate clients (the official mobile apps historically, some remote publishing tools, some plugins such as Jetpack in older modes) but is frequently abused:
- Pingback amplification attacks using pingback.ping and system.multicall to multiply requests and produce DDoS/amplification.
- Brute-force login attempts using wp.getUsersBlogs or other wp. methods.
- Unwanted attack surface for remote code paths that most sites do not need.
Completely disabling xmlrpc.php is simple but sometimes unacceptable because some valid clients or plugins still rely on a small set of xmlrpc methods. The best practice is to restrict xmlrpc.php to only the minimum set of methods you need, and to block known-abused methods (especially pingback. and system.multicall). This article gives several robust ways to do that: WordPress-level filtering, server-level rules (Nginx and Apache/mod_security), per-site IP-only rules, and test examples.
Strategy summary
- Identify which xmlrpc methods you need (mobile app? remote publishing? Jetpack?).
- At the WordPress level, remove or allow only the methods you require using the xmlrpc_methods filter.
- At the server level, block known-abused methods (pingback. and system.multicall) or implement a request-body inspection allowing only a whitelist of methods.
- Optionally, restrict access to /xmlrpc.php by IP if the remote client(s) have fixed IPs.
- Test thoroughly with curl and monitor logs.
1) WordPress-level restriction (recommended baseline)
WordPress exposes a filter named xmlrpc_methods. It provides a list (associative array) of method names to handler functions. You can use that filter to remove dangerous methods or to create a whitelist of allowed methods. Applying this filter is the most compatible approach because it runs inside WordPress and does not require server configuration.
Remove specific abused methods (quick, safe)
This example unsets the most problematic xmlrpc methods: pingback. and system.multicall. Place the code in a small mu-plugin (must-use plugin) or in a site-specific plugin avoid putting it in a themes functions.php so it survives theme changes.
lt?php / mu-plugin or site plugin: block pingbacks and system.multicall / add_filter(xmlrpc_methods, function(methods){ // Remove pingback methods unset(methods[pingback.ping]) unset(methods[pingback.extensions.getPingbacks]) // Remove system.multicall to prevent method-batching amplification unset(methods[system.multicall]) return methods })
Whitelist-only approach (most restrictive)
If you know exactly which xmlrpc methods your site needs, build a whitelist. This removes every method except those listed. This is safest but you must include any method required by plugin(s) or external services you use.
lt?php / mu-plugin: only allow a small set of xmlrpc methods Edit allowed_methods to include the keys you need. / add_filter(xmlrpc_methods, function(methods){ // Only these xmlrpc methods will remain (adjust as needed) allowed_methods = array( wp.getUsersBlogs, wp.getPosts, wp.getPost, wp.newPost, wp.editPost, wp.deletePost, wp.getCategories, wp.getTags, wp.newMediaObject, wp.getMediaLibrary, // add other wp. methods you require ) // Intersect current methods with the allowed list methods = array_intersect_key(methods, array_flip(allowed_methods)) return methods })
Important notes about the WordPress-filter approach
- It blocks by method name inside WordPress logic. This means the request still reaches PHP but WordPress will return an XML-RPC fault for disallowed methods.
- It is fully compatible with WordPress authentication and capabilities checks already performed by the built-in handlers.
- Because requests still hit PHP, attackers can still consume some CPU/IO, so pairing this with server-level blocking is advised for high-traffic attack situations.
- If you use plugins that rely on xmlrpc (Jetpack, remote publishing tools), check their docs to identify required methods and add them to the allow list.
2) Server-level blocking — Nginx examples
Blocking at the web-server level is more efficient because it prevents PHP from being invoked. Nginx allows access to the request body via the request_body variable (it must read the body first). A common and effective approach is to inspect request_body and block specific methodName values or allow only a small whitelist.
Block pingback.ping and system.multicall (simple, common)
# inside your server block location = /xmlrpc.php { # read client body for request_body usage client_body_buffer_size 128k # Block pingback.ping or system.multicall anywhere in the body if (request_body ~ pingback.ping) { return 403 } if (request_body ~ system.multicall) { return 403 } # Let PHP-FPM handle allowed requests include fastcgi_params fastcgi_pass unix:/var/run/php-fpm.sock fastcgi_param SCRIPT_FILENAME /path/to/wordpress/xmlrpc.php }
Note: The regex uses case-insensitive matching (~). You can expand checks to block other method names. Nginx evaluates if statements sequentially returning 403 prevents PHP execution.
Whitelist xmlrpc methods at Nginx level (most restrictive)
This example allows only requests that contain one of the listed methodName entries all others are rejected. Adjust the allowed list to your needs.
location = /xmlrpc.php { client_body_buffer_size 128k # Allowed method names (pipe-separated) set xmlrpc_allowed 0 if (request_body ~ (wp.getPosts wp.newPost wp.getUsersBlogs )) { set xmlrpc_allowed 1 } if (xmlrpc_allowed = 0) { return 403 } include fastcgi_params fastcgi_pass unix:/var/run/php-fpm.sock fastcgi_param SCRIPT_FILENAME /path/to/wordpress/xmlrpc.php }
Caveats:
- Large request bodies and streaming clients may require adjusting buffer sizes test with real clients.
- Some clients send methodName values with different whitespace/newlines — use tolerant regex patterns.
3) Server-level blocking — Apache and mod_security
Apaches mod_rewrite cannot inspect POST bodies. Use mod_security (WAF) to inspect the XML body and block or allow methods. If you dont run mod_security, consider using an Apache
mod_security rule to block pingback and system.multicall
# Example mod_security (SecRule) rule in your mod_security config SecRule REQUEST_URI @endsWith /xmlrpc.php phase:2,id:100001,log,deny,msg:Blocked xmlrpc pingback/multicall, chain SecRule REQUEST_BODY @rx (pingback.pingsystem.multicall) t:none
This rule denies any POST to /xmlrpc.php whose body contains pingback.ping or system.multicall. Expand the regex to detect additional method names you want to block.
4) .htaccess / Apache access restrictions (IP-based)
If only a small set of external IPs needs xmlrpc access (for example, a remote publishing system on static IPs), restrict xmlrpc.php to those IPs.
ltFiles xmlrpc.phpgt ltRequireAllgt Require all denied # Allow specific IPs or CIDR ranges Require ip 203.0.113.5 Require ip 198.51.100.0/24 lt/RequireAllgt lt/Filesgt
This is extremely effective (prevents any access from unknown IPs), but only suitable when the legitimate clients use fixed IPs.
5) Returning a graceful XML-RPC fault from PHP for blocked methods
If you prefer requests to reach PHP but want an immediate XML-RPC fault for blocked methods, hook early and return a fault. This keeps logs inside PHP and is cleaner for remote clients that expect XML-RPC responses.
lt?php / Return XML-RPC fault for disallowed methods early. / add_filter(xmlrpc_methods, function(methods){ // Let WordPress register its usual handlers, // well wrap the handler bodies using xmlrpc_call if needed. return methods }) // Use this action to inspect the raw XML and die with a fault add_action(xmlrpc_call, function(method){ blocked = array(pingback.ping,system.multicall) if (in_array(method, blocked, true)) { xmlrpc_error(403, This XML-RPC method is disabled on this site.) exit } }, 1)
Note: Some WordPress versions may not define xmlrpc_call in the same way prefer the xmlrpc_methods filter for compatibility. If using direct XML inspection, ensure the hook runs before handlers execute.
6) Practical testing and verification
Always test changes on staging before applying to production. Use curl to test allowed and blocked methods.
Example: XML-RPC call to wp.getUsersBlogs (test expected allowed)
curl -s -X POST https://example.com/xmlrpc.php -H Content-Type: text/xml -dwp.getUsersBlogs username password
Example: XML-RPC pingback attempt (should be blocked)
curl -s -X POST https://example.com/xmlrpc.php -H Content-Type: text/xml -d# Expect a 403 (server-level block) or an XML-RPC fault response from WordPress. pingback.ping http://attacker.example/ https://example.com/target-post/
7) Detecting usage and monitoring
Before you remove or block methods, check your server logs to see which xmlrpc methods are being called. Typical places:
- Web server access logs (look for POST /xmlrpc.php requests).
- mod_security logs (if enabled).
- WordPress logs when running a plugin or mu-plugin that logs xmlrpc_method calls.
You can add temporary logging in a mu-plugin to record the xmlrpc method names and the calling IP, user agent and time before you block. Example:
lt?php add_filter(xmlrpc_methods, function(methods){ // Log method usage by wrapping handlers (simple approach) foreach (methods as name =gt handler) { orig = handler methods[name] = function() use (name, orig) { error_log(xmlrpc method called: {name} from . _SERVER[REMOTE_ADDR]) // Call original handler args = func_get_args() return call_user_func_array(orig, args) } } return methods })
8) Additional recommendations and hardening tips
- Disable Pingbacks in Settings: In WordPress Admin → Settings → Discussion, uncheck Allow link notifications from other blogs (pingbacks and trackbacks). This reduces some pingback activity at the WordPress level.
- Pair WordPress and server-level controls: Use the xmlrpc_methods filter plus a server block (Nginx or mod_security) for best protection and efficiency.
- Limit login attempts: Use rate-limiting for authentication attempts (fail2ban for log parsing or web-application firewall throttle rules).
- Monitor for system.multicall: Because system.multicall multiplies attack impact, ensure it is blocked if you do not explicitly need batch calls.
- Fallback plan: If legitimate functionality breaks, re-enable only the specific method(s) required and re-test.
9) Common method lists (for reference)
Typical WordPress xmlrpc methods:
- wp. — methods for posting, editing, media, categories, tags, posts retrieval (wp.newPost, wp.editPost, wp.getPosts, wp.newMediaObject, etc.)
- pingback.ping and pingback.extensions.getPingbacks — pingback protocol
- system.listMethods, system.multicall — XML-RPC system methods
- blogger. — Blogger API compatibility
- mt. — MovableType compatibility
If you only use remote publishing or a mobile client, you most likely only need a handful of wp. methods and can safely remove the rest.
10) Troubleshooting
- If legitimate clients report 403 or method not found, inspect server logs and temporarily revert to a permissive configuration while you identify required methods.
- If Nginx request_body is empty, ensure the configuration does not stream bodies to a file only and client_body_buffer_size is adequate test with various clients.
- When using mod_security, watch the audit log to see which rule triggered and tune rules and regex accordingly.
- If you need further granularity (rate-limiting by IP for xmlrpc.php), add fail2ban rules or WAF throttling for that endpoint.
Appendix — Quick reference code snippets
Block pingback and system.multicall in PHP (copy-friendly)
lt?php add_filter(xmlrpc_methods, function(methods){ unset(methods[pingback.ping]) unset(methods[pingback.extensions.getPingbacks]) unset(methods[system.multicall]) return methods })
Nginx: block pingback and system.multicall
location = /xmlrpc.php { client_body_buffer_size 128k if (request_body ~ pingback.ping) { return 403 } if (request_body ~ system.multicall) { return 403 } include fastcgi_params fastcgi_pass unix:/var/run/php-fpm.sock fastcgi_param SCRIPT_FILENAME /path/to/wordpress/xmlrpc.php }
Apache mod_security: block xmlrpc pingback/multicall
SecRule REQUEST_URI @endsWith /xmlrpc.php phase:2,id:100001,log,deny,msg:Blocked xmlrpc pingback/multicall,chain SecRule REQUEST_BODY @rx (pingback.pingsystem.multicall) t:none
Final notes
Partially blocking xmlrpc.php while allowing only necessary methods gives you a good balance between compatibility and security. Start by identifying which xmlrpc methods you actually need, implement a WordPress-level whitelist or method removal, and then harden the endpoint at the web-server/WAF level to avoid unnecessary PHP processing. Test carefully and monitor logs after deploying changes.
|
Acepto donaciones de BAT's mediante el navegador Brave 🙂 |