WordPress REST API Security: Risks & Hardening Guide

On This Page

Since WordPress 4.7, the REST API has been enabled by default. It powers the Block Editor (Gutenberg), allows “Headless” WordPress setups, and lets plugins communicate with external services.

However, by default, the REST API is also publicly accessible.

Anyone—including hackers and bots—can query your site’s API endpoints (/wp-json/) to extract data about your users, posts, and taxonomy structure. While this isn’t always a “vulnerability” in the strict sense, it is a massive information leak that aids attackers in the reconnaissance phase.

In this guide, we’ll explore the specific risks of an open REST API and provide the code snippets you need to lock it down.


The Core Risk: Information Disclosure

The REST API is designed to be open. If you visit https://yoursite.com/wp-json/, you get a JSON response listing all available routes and endpoints.

While convenient for developers, this openness creates three major security problems:

1. User Enumeration (The #1 Threat)

By default, WordPress allows anyone to query the users endpoint:

GET /wp-json/wp/v2/users

The Risk: This request returns a list of all users who have published posts, including their User IDs, Display Names, and most critically, their Usernames (slugs).

Once a hacker has your username (e.g., admin_ted), they have 50% of the credentials needed to log in. They can then launch a targeted Brute Force attack on that specific account.

FunSentry’s Scan:

When you run a FunSentry scan, we specifically target this endpoint. If we receive a 200 OK status and a list of users, we flag your site as “Vulnerable to User Enumeration.”

2. Content Scraping

Scrapers can use /wp-json/wp/v2/posts to download your entire content library in a structured format, bypassing your theme’s frontend design. This makes it incredibly easy for content thieves to clone your site.

3. DDoS and Resource Exhaustion

API requests can be more resource-intensive than standard page loads because they often trigger complex database queries. Attackers can flood your API endpoints to exhaust your server’s CPU and memory, taking your site offline.


How to Secure the REST API (Without Breaking Your Site)

Important: You generally cannot completely disable the REST API. The WordPress Block Editor (Gutenberg), WooCommerce, and many modern plugins (like Contact Form 7) rely on it to function.

Instead of disabling it, we must harden it.

1. Disable User Enumeration Only

This is the most critical fix. We want to keep the API open for functionality but stop it from revealing user data.

Add this code snippet to your theme’s functions.php file or a custom plugin:

PHP

/**
 * Disable REST API User Enumeration
 * Blocks access to /wp-json/wp/v2/users for unauthenticated requests
 */
add_filter( 'rest_endpoints', function( $endpoints ) {
    if ( isset( $endpoints['/wp/v2/users'] ) && ! is_user_logged_in() ) {
        unset( $endpoints['/wp/v2/users'] );
    }
    if ( isset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] ) && ! is_user_logged_in() ) {
        unset( $endpoints['/wp/v2/users/(?P<id>[\d]+)'] );
    }
    return $endpoints;
});

What this does:

It removes the /users endpoint from the API registry unless the person requesting it is currently logged in as an administrator or editor. Bots scanning your site will now get a 404 Not Found.

2. Disable REST API for Non-Logged-In Users (Strict Mode)

If your site does not use a headless frontend and you want maximum security, you can block all anonymous REST API access.

Warning: This may break some public-facing plugins that use AJAX via the REST API. Test thoroughly!

PHP

/**
 * Require Authentication for All REST API Requests
 */
add_filter( 'rest_authentication_errors', function( $result ) {
    // If a valid authentication is already present, allow it.
    if ( ! empty( $result ) ) {
        return $result;
    }

    // If the user is not logged in, block the request.
    if ( ! is_user_logged_in() ) {
        return new WP_Error(
            'rest_not_logged_in',
            'You are not currently logged in.',
            array( 'status' => 401 )
        );
    }

    return $result;
});

What this does:

Any request to /wp-json/ from an unauthenticated user gets a 401 Unauthorized error. This effectively hides your API from the public internet while allowing the Block Editor (which is authenticated) to work for you.

3. Restrict JSONP Support

JSONP (JSON with Padding) is an older technique used to bypass cross-domain policies. It is rarely needed in modern WordPress setups but is enabled by default.

PHP

// Remove JSONP support
remove_filter( 'rest_jsonp_enabled', '_return_true' );

Using “Application Passwords” Safely

WordPress 5.6 introduced Application Passwords, allowing external systems to authenticate via the REST API without using your main password.

The Risk:

If a hacker tricks an administrator into generating an application password (social engineering), or if they gain access to a less-secure system you’ve connected to, they have full admin access to your site via the API.

Best Practice:

  1. Go to Users → Profile.
  2. Scroll down to Application Passwords.
  3. Audit this list regularly. Revoke any passwords for apps you no longer use.
  4. If you don’t use external integrations, disable this feature entirely using a plugin like “Disable Application Passwords.”

Summary Checklist

ActionImpact on FunctionalitySecurity Gain
Disable /users endpointNone (Safe)⭐⭐⭐⭐⭐ (Stops user harvesting)
Require Auth for all APIHigh (May break plugins)⭐⭐⭐⭐⭐ (Complete API lockdown)
Disable JSONPLow⭐⭐ (Good hygiene)
Audit App PasswordsNone⭐⭐⭐ (Prevents backdoor access)

The REST API is a powerful tool, but it shouldn’t be an open book. At a minimum, every WordPress administrator should block the /users endpoint to prevent easy username harvesting.

Is your User Data Leaking?

Don’t wait for a brute force attack. Run a free scan at FunSentry to instantly check if your /wp-json/wp/v2/users endpoint is exposing your admin usernames to the world.