The Security Vulnerability of Default WP-JSON Endpoints
Since WordPress 4.7, the WordPress REST API has been enabled by default on all WordPress installations. While this headless functionality powers modern decoupled applications and Gutenberg block interactions, it introduces significant security exposures when left completely unhardened. Out of the box, any automated scanning bot or malicious actor can visit example.com/wp-json/wp/v2/users and instantly extract your complete administrative username database, user IDs, and author slugs, providing attackers with 50% of the credentials required for automated brute-force attacks.
Furthermore, unauthenticated automated scrapers frequently abuse heavy endpoints like /wp-json/wp/v2/posts or third-party plugin routes to scrape content and trigger high database loads that cause server denial-of-service (DoS). In this tutorial, we implement battle-tested PHP snippets, Apache directives, and Cloudflare rules to lock down your REST endpoints without breaking legitimate administrative functions.
Method 1: Blocking Public User Enumeration via functions.php
The most dangerous default endpoint is the user enumeration route. Add the following security filter to your active theme’s functions.php or deploy it inside a dedicated must-use (MU) plugin:
<?php
/**
* Plugin Name: Hardened WordPress REST API Shield
* Description: Blocks unauthenticated access to sensitive WP-JSON user endpoints.
*/
add_filter('rest_authentication_errors', function($access) {
// If an error is already returned, do not override it
if (is_wp_error($access)) {
return $access;
}
// Allow logged-in administrators and authorized users full access
if (is_user_logged_in()) {
return $access;
}
// Extract requested REST route
$rest_route = $_SERVER['REQUEST_URI'] ?? '';
// Strictly forbid unauthenticated requests to user directories
if (strpos($rest_route, '/wp/v2/users') !== false) {
return new WP_Error(
'rest_forbidden_context',
__('Access to the user directory is restricted to authorized administrators.', 'syedsworld'),
['status' => 401]
);
}
return $access;
});
Method 2: Restricting REST API to Authenticated Users Only
If your website is a traditional blog or marketing site that does not use headless front-ends, public mobile applications, or external webhooks, you can restrict the entire REST API to logged-in sessions only:
add_filter('rest_authentication_errors', function($result) {
if (!empty($result)) {
return $result;
}
// Check if user is logged into WordPress
if (!is_user_logged_in()) {
return new WP_Error(
'rest_not_logged_in',
__('You are not currently authenticated to query this REST endpoint.', 'syedsworld'),
['status' => 401]
);
}
return $result;
});
is_user_logged_in() so your Gutenberg editor functions perfectly while blocking public bots.
Method 3: Server-Level Apache .htaccess Hardening
To eliminate PHP execution overhead entirely, drop malicious user-probing bots at the web server layer before WordPress or database queries are even initialized:
# Block WP-JSON User Enumeration at Server Layer
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_METHOD} GET
RewriteCond %{QUERY_STRING} (?:^|&)rest_route=/wp/v2/users [NC,OR]
RewriteCond %{REQUEST_URI} ^/wp-json/wp/v2/users [NC]
RewriteRule .* - [F,L]
</IfModule>
Method 4: Cloudflare Web Application Firewall (WAF) Rule
If your domain is proxied through Cloudflare, create an Edge WAF rule to block user enumeration globally at Cloudflare's edge data centers before the request ever reaches your origin server:
- Field: URI Path
- Operator: contains
- Value:
/wp-json/wp/v2/users - AND: Cookie does not contain
wordpress_logged_in_ - Action: Block (403 Forbidden)
Frequently Asked Questions (REST API Security FAQ)
Does blocking /wp-json/ hurt my SEO or Google indexing?
No. Googlebot indexes your web pages by rendering your public HTML, CSS, and JavaScript. Google does not require access to your raw /wp-json/wp/v2/users endpoint to index your content.
What happens if a plugin requires public REST API access?
You can whitelist specific plugin namespaces in your PHP filter. For example, if WooCommerce or a newsletter plugin needs access to /wp-json/wc/v3, inspect the URI and permit requests matching that specific namespace while keeping core user routes locked down.
How do I test if my user endpoint is successfully secured?
Open an incognito browser window and navigate to https://yourdomain.com/wp-json/wp/v2/users. If hardened correctly, you should receive a clean 401 Unauthorized or 403 Forbidden JSON payload rather than an array of user objects.
Rate Limiting & DDoS Prevention for WP-JSON
Beyond blocking user enumeration, protect your server against automated high-volume DDoS attacks by implementing rate limiting at the Nginx or Apache layer. Restrict unauthenticated clients to a maximum of 15 requests per minute against /wp-json/ endpoints to prevent database exhaustion during automated bot sweeps.