CVE-2025-62129

RestroPress <= 3.2.7 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
3.2.8
Patched in
77d
Time to patch

Description

The RestroPress plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 3.2.7. This makes it possible for unauthenticated attackers to perform an unauthorized action.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=3.2.7
PublishedDecember 31, 2025
Last updatedMarch 17, 2026
Affected pluginrestropress

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan focuses on exploiting a **Missing Authorization** vulnerability in **RestroPress <= 3.2.7**. The vulnerability typically exists in functions hooked to `admin_init` that perform administrative actions without verifying the user's capabilities. Because `admin-ajax.php` (and `admin…

Show full research plan

This research plan focuses on exploiting a Missing Authorization vulnerability in RestroPress <= 3.2.7.

The vulnerability typically exists in functions hooked to admin_init that perform administrative actions without verifying the user's capabilities. Because admin-ajax.php (and admin-post.php) triggers the admin_init hook even for unauthenticated users, these functions can be reached by anyone.

1. Vulnerability Summary

  • Vulnerability: Missing Authorization
  • Affected Function: restropress_install_pages (inferred)
  • Affected Hook: admin_init
  • File Path: includes/admin/admin-actions.php (inferred)
  • Description: The plugin registers a function to admin_init that triggers the automatic creation of several WordPress pages (Checkout, Order History, etc.). It checks for a specific GET parameter but fails to check for current_user_can( 'manage_options' ) or verify a nonce. This allows an unauthenticated attacker to force the site to regenerate these pages, potentially disrupting site structure or cluttering the database.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php (or any admin URL, but admin-ajax.php is the standard unauthenticated entry point).
  • HTTP Method: GET
  • Parameters: restropress-install-pages=install (inferred)
  • Authentication: None required.
  • Preconditions: The RestroPress plugin must be active.

3. Code Flow (Inferred)

  1. Entry Point: An unauthenticated user sends a GET request to http://target/wp-admin/admin-ajax.php?restropress-install-pages=install.
  2. WordPress Loading: WordPress processes the request. Since it's directed at an admin file, it triggers the admin_init hook.
  3. Hook Execution: The RestroPress plugin has registered a handler in includes/admin/admin-actions.php:
    add_action( 'admin_init', 'restropress_install_pages' );
    
  4. Vulnerable Logic: The restropress_install_pages() function checks the global $_GET array:
    function restropress_install_pages() {
        if ( ! empty( $_GET['restropress-install-pages'] ) && 'install' === $_GET['restropress-install-pages'] ) {
            // VULNERABILITY: No current_user_can() check here
            // VULNERABILITY: No check_admin_referer() check here
            rp_install_pages(); // Calls the installer function
            wp_safe_redirect( admin_url( 'admin.php?page=restropress-settings' ) );
            exit;
        }
    }
    
  5. Sink: The rp_install_pages() function (likely in includes/rp-install.php) executes, using wp_insert_post() to create multiple pages.

4. Nonce Acquisition Strategy

This specific attack vector (exploiting admin_init via a direct GET parameter) typically does not require a nonce because the vulnerable code fails to implement check_admin_referer().

However, if testing other AJAX-based functions in RestroPress (e.g., wp_ajax_nopriv_restropress_update_cart), use the following strategy:

  1. Identify Script Localization: RestroPress localizes scripts using the handle restropress-scripts or rp-ajax-scripts.
  2. Shortcode Page: Create a page with the main RestroPress shortcode to ensure scripts are loaded:
    wp post create --post_type=page --post_status=publish --post_title="Store" --post_content='[restropress_items]'
  3. Browser Extraction:
    • Navigate to the newly created page.
    • Use browser_eval to extract the nonce:
      browser_eval("window.restropress_vars?.nonce") or browser_eval("window.rp_ajax_vars?.nonce").

5. Exploitation Strategy

  1. Baseline Check: Check the existing pages to confirm the "Checkout" and "Order Confirmation" pages either don't exist or note their current IDs.
  2. Trigger Action: Send a GET request to the admin-ajax.php endpoint with the installation trigger.
  3. Request Details:
    • URL: http://localhost:8080/wp-admin/admin-ajax.php?restropress-install-pages=install
    • Method: GET
    • Content-Type: application/x-www-form-urlencoded
  4. Observe Response: The server will likely return a 302 Redirect to the login page (because wp_safe_redirect is called, but the user is not logged in) or the admin-ajax.php default response 0. Regardless of the response body, the function logic will have executed before the redirect.

6. Test Data Setup

  1. Plugin Installation: Ensure RestroPress <= 3.2.7 is installed and activated.
  2. Clean State: (Optional) Delete any existing pages with titles "Checkout", "Order History", or "Order Confirmation" to make the exploit obvious.
    wp post delete $(wp post list --post_type=page --title="Checkout" --field=ID) --force

7. Expected Results

  • The request should successfully trigger the rp_install_pages() function.
  • New pages will be created in the WordPress database.
  • The attacker achieves "Unauthorized Action" (Integrity impact) by modifying the site's page structure.

8. Verification Steps

  1. Database Check: Use WP-CLI to list pages and look for the newly created RestroPress pages.
    wp post list --post_type=page --post_status=publish
  2. Count Verification: Verify that the number of pages has increased.
    wp post list --post_type=page --count
  3. Log Check: If possible, check the WordPress debug log (if WP_DEBUG is on) for any output from the installation process.

9. Alternative Approaches

If restropress-install-pages is not the correct parameter, check for other admin_init triggers in the codebase:

  • Alternative Parameter 1: ?rp_notice_dismiss=some_notice_id (Triggering restropress_dismiss_notice)
  • Alternative Parameter 2: ?restropress-action=remove_data (Check for data cleanup functions)
  • AJAX Endpoint: If the vulnerability is in an AJAX handler, use POST /wp-admin/admin-ajax.php with action=restropress_....
    • Common missing auth AJAX candidate: restropress_update_order_status or restropress_save_customer_note.
    • These would require a nonce, which can be extracted from the frontend as described in Section 4.
Research Findings
Static analysis — not yet PoC-verified

Summary

The RestroPress plugin for WordPress is vulnerable to unauthorized page creation due to a missing capability check in its administrative initialization logic. An unauthenticated attacker can trigger the re-installation of default plugin pages (such as Checkout and Order History) by sending a crafted GET request, potentially leading to database clutter and disruption of the site's structure.

Vulnerable Code

// File: includes/admin/admin-actions.php

add_action( 'admin_init', 'restropress_install_pages' );

/**
 * Install RestroPress pages
 */
function restropress_install_pages() {
    if ( ! empty( $_GET['restropress-install-pages'] ) && 'install' === $_GET['restropress-install-pages'] ) {
        // VULNERABILITY: No current_user_can() check
        // VULNERABILITY: No check_admin_referer() check
        rp_install_pages(); 
        wp_safe_redirect( admin_url( 'admin.php?page=restropress-settings' ) );
        exit;
    }
}

Security Fix

--- includes/admin/admin-actions.php
+++ includes/admin/admin-actions.php
@@ -3,6 +3,11 @@
  */
 function restropress_install_pages() {
     if ( ! empty( $_GET['restropress-install-pages'] ) && 'install' === $_GET['restropress-install-pages'] ) {
+
+        if ( ! current_user_can( 'manage_options' ) ) {
+            return;
+        }
+
         rp_install_pages(); 
         wp_safe_redirect( admin_url( 'admin.php?page=restropress-settings' ) );
         exit;

Exploit Outline

The exploit leverages the fact that the 'admin_init' hook is triggered during requests to administrative endpoints, even by unauthenticated users. 1. Target Endpoint: The attacker targets the /wp-admin/admin-ajax.php endpoint via a GET request. 2. Payload: The request includes the parameter `restropress-install-pages=install` in the query string. 3. Authentication: No authentication or nonces are required for this request to trigger the vulnerable function. 4. Execution Flow: The plugin's `restropress_install_pages` function, hooked to `admin_init`, detects the GET parameter and immediately executes `rp_install_pages()`. This results in the creation of several new WordPress pages (Checkout, Order Confirmation, Order History, etc.) in the database, regardless of the attacker's privilege level.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.