CVE-2026-3550

RockPress <= 1.0.17 - Missing Authorization to Authenticated (Subscriber+) Arbitrary Modification via AJAX Actions

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
1.0.18
Patched in
1d
Time to patch

Description

The RockPress plugin for WordPress is vulnerable to Missing Authorization in all versions up to, and including, 1.0.17. This is due to missing capability checks on multiple AJAX actions (rockpress_import, rockpress_import_status, rockpress_last_import, rockpress_reset_import, and rockpress_check_services) combined with the plugin's nonce being exposed to all authenticated users via an unconditionally enqueued admin script. The plugin enqueues the 'rockpress-admin' script on all admin pages (including profile.php) without any page or capability restrictions, and the nonce for the 'rockpress-nonce' action is passed to this script via wp_localize_script. Since the AJAX handlers only verify this nonce and do not check current_user_can(), any authenticated user, including Subscribers, can extract the nonce from any admin page's HTML source and use it to trigger imports, reset import data (deleting options), check service connectivity, and read import status information. This makes it possible for authenticated attackers, with Subscriber-level access and above, to trigger resource-intensive import operations, reset import tracking data, and perform system connection checks that should be restricted to administrators.

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<=1.0.17
PublishedMarch 19, 2026
Last updatedMarch 20, 2026
Affected pluginft-rockpress

What Changed in the Fix

Changes introduced in v1.0.18

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Vulnerability Research Plan: CVE-2026-3550 (RockPress Arbitrary Modification) ## 1. Vulnerability Summary RockPress (<= 1.0.17) contains multiple missing authorization vulnerabilities in its AJAX handlers. The plugin fails to perform capability checks (e.g., `current_user_can()`) in five sensitiv…

Show full research plan

Vulnerability Research Plan: CVE-2026-3550 (RockPress Arbitrary Modification)

1. Vulnerability Summary

RockPress (<= 1.0.17) contains multiple missing authorization vulnerabilities in its AJAX handlers. The plugin fails to perform capability checks (e.g., current_user_can()) in five sensitive AJAX actions, relying solely on nonce verification. However, the nonce required for these actions is unconditionally enqueued for all authenticated users on any admin page (including profile.php). This allows any authenticated user (Subscriber level and above) to trigger resource-intensive imports, read internal status, or delete plugin configuration options.

2. Attack Vector Analysis

  • Endpoints: /wp-admin/admin-ajax.php
  • AJAX Actions:
    • rockpress_check_services (connectivity test)
    • rockpress_import (trigger background import)
    • rockpress_import_status (read import progress)
    • rockpress_last_import (read last import time)
    • rockpress_reset_import (delete import configuration/status)
  • Vulnerable Parameter: nonce (required for verification)
  • Required Authentication: Any authenticated user (e.g., Subscriber).
  • Preconditions: The plugin must be active and configured with some default options (to demonstrate modification).

3. Code Flow

  1. Nonce Exposure: In includes/admin/admin-scripts.php, the class RockPress_Admin_Scripts hooks into admin_enqueue_scripts. The enqueue() method calls wp_enqueue_script( 'rockpress-admin', ... ) without any capability or page checks. The localize() method then uses wp_localize_script to bind a nonce created with the action 'rockpress-nonce' to the JavaScript variable rockpress_vars.nonce.
  2. AJAX Registration: In includes/class-rockpress-import.php, actions are registered for wp_ajax_rockpress_import, wp_ajax_rockpress_import_status, wp_ajax_rockpress_last_import, and wp_ajax_rockpress_reset_import. In includes/admin/admin-ajax.php, the action wp_ajax_rockpress_check_services is registered.
  3. Vulnerable Handler (Example: ajax_reset_import):
    public static function ajax_reset_import() {
        if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'rockpress-nonce' ) ) {
            die( esc_html__( 'Insufficient Permissions', 'ft-rockpress' ) );
        }
        delete_option( 'rockpress_import_in_progress' );
        delete_option( 'rockpress_current_import' );
        delete_option( 'rockpress_last_import' );
        // ...
    }
    
    The handler checks the nonce but lacks any current_user_can( 'manage_options' ) check.

4. Nonce Acquisition Strategy

The nonce is localized in the rockpress_vars object on any admin page.

  1. Access: Log into the WordPress site as a Subscriber.
  2. Navigation: Navigate to /wp-admin/profile.php.
  3. Extraction: Use browser_eval to extract the nonce from the global JavaScript scope.
    • JS Variable: window.rockpress_vars
    • Nonce Key: nonce
    • Command: browser_eval("window.rockpress_vars?.nonce")

5. Exploitation Strategy

We will target rockpress_reset_import because it has a measurable impact: deleting existing options.

  1. Pre-Exploit Setup: Use WP-CLI to create a dummy import timestamp so there is something to delete.
  2. Authentication: Use browser_navigate and browser_type to log in as a Subscriber.
  3. Nonce Extraction: Navigate to /wp-admin/profile.php and run the browser_eval command mentioned above.
  4. The Attack: Send a POST request to admin-ajax.php using the http_request tool.
    • URL: {{BASE_URL}}/wp-admin/admin-ajax.php
    • Method: POST
    • Headers: Content-Type: application/x-www-form-urlencoded
    • Body: action=rockpress_reset_import&nonce={{EXTRACTED_NONCE}}
  5. Verification: Check if the target options have been deleted using WP-CLI.

6. Test Data Setup

  1. Create Subscriber: wp user create attacker attacker@example.com --role=subscriber --user_pass=password123
  2. Set Dummy Options:
    wp option update rockpress_last_import "2023-01-01 12:00:00"
    wp option update rockpress_import_in_progress "Test Import"
    
  3. Ensure Plugin Settings: Ensure the plugin is active: wp plugin activate ft-rockpress

7. Expected Results

  • The AJAX request should return a 200 OK response.
  • The response body should contain the string Never (from esc_html_e( 'Never', 'rockpress' ); in ajax_reset_import).
  • The options rockpress_last_import and rockpress_import_in_progress should be removed from the database.

8. Verification Steps

  1. Check Options via WP-CLI:
    wp option get rockpress_last_import --format=json
    wp option get rockpress_import_in_progress --format=json
    
    • Expected Outcome: Both should return an error or empty result indicating the option does not exist.
  2. Check Response Body: Verify the http_request output contains the text Never.

9. Alternative Approaches

If rockpress_reset_import fails to demonstrate the vulnerability convincingly, target rockpress_check_services:

  • Action: rockpress_check_services
  • Payload: action=rockpress_check_services&nonce={{EXTRACTED_NONCE}}
  • Effect: This will trigger RockPress()->rock->test(). While harder to verify via DB, if the Rock API URL is set to an attacker-controlled listener (e.g., via wp option update rockpress_rock_url), this results in SSRF.
  • Status Read: Target rockpress_import_status to leak the current rockpress_import_in_progress option value, which might contain sensitive status strings.

Check if your site is affected.

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