CVE-2026-25364

Client Invoicing by Sprout Invoices <= 20.8.8 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
20.8.9
Patched in
12d
Time to patch

Description

The Client Invoicing by Sprout Invoices plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 20.8.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<=20.8.8
PublishedFebruary 15, 2026
Last updatedFebruary 26, 2026
Affected pluginsprout-invoices

Source Code

WordPress.org SVN
Research Plan
Unverified

# Research Plan: CVE-2026-25364 - Sprout Invoices Missing Authorization ## 1. Vulnerability Summary The **Client Invoicing by Sprout Invoices** plugin (up to version 20.8.8) contains a "Missing Authorization" vulnerability. This occurs because one or more AJAX handlers are registered via `wp_ajax_n…

Show full research plan

Research Plan: CVE-2026-25364 - Sprout Invoices Missing Authorization

1. Vulnerability Summary

The Client Invoicing by Sprout Invoices plugin (up to version 20.8.8) contains a "Missing Authorization" vulnerability. This occurs because one or more AJAX handlers are registered via wp_ajax_nopriv_ (allowing unauthenticated access) but fail to perform a capability check (e.g., current_user_can( 'manage_options' )) or verify the caller's authority before executing sensitive logic. An unauthenticated attacker can leverage this to perform unauthorized actions, such as modifying plugin settings or manipulating invoice data.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: si_save_settings or si_ajax_save_settings (Inferred based on common plugin patterns and the "unauthorized action" description).
  • Vulnerable Hook: wp_ajax_nopriv_si_save_settings or wp_ajax_nopriv_sa_save_settings.
  • Payload Parameter: Typically $_POST['settings'] or specific keys like $_POST['option_name'] and $_POST['option_value'].
  • Authentication Level: Unauthenticated (Nopriv).
  • Preconditions: The plugin must be active.

3. Code Flow

  1. Entry Point: The plugin registers an AJAX handler using add_action( 'wp_ajax_nopriv_si_save_settings', ... ) in an initialization file (e.g., controllers/settings/Settings.php or inc/SI_Settings.php).
  2. Missing Check: The callback function (e.g., SI_Settings::save_settings) is invoked. It lacks a current_user_can() check.
  3. Data Processing: The function reads input from $_POST.
  4. Sink: The function calls update_option() or a internal wrapper like SI_Options::update_settings(), allowing the attacker to overwrite plugin configurations.

4. Nonce Acquisition Strategy

If the plugin requires a nonce for the AJAX action, it is typically localized in the WordPress header or footer using wp_localize_script.

  • JS Variable Name: si_js_vars or sprout_invoices_vars (Inferred).
  • Nonce Key: security, nonce, or settings_nonce.
  • Acquisition Steps:
    1. Identify Script Trigger: Sprout Invoices usually enqueues its settings scripts on its own admin pages, but unauthenticated nonces might be found on pages where invoices or leads are rendered.
    2. Create Trigger Page: Create a page with the Sprout Invoices lead shortcode (common in this plugin):
      wp post create --post_type=page --post_status=publish --post_content='[sprout_invoice_lead]'
    3. Navigate: Open the newly created page in the browser.
    4. Extract: Use browser_eval to fetch the nonce:
      browser_eval("window.si_js_vars?.security || window.sprout_invoices_vars?.nonce")

5. Exploitation Strategy

We will attempt to modify a specific plugin setting to demonstrate unauthorized access.

  • Request Type: POST
  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Payload:
    action=si_save_settings&nonce=[EXTRACTED_NONCE]&settings[site_currency]=EVIL
    
    (Note: site_currency is a standard setting in Sprout Invoices. Changing it to a dummy value like 'EVIL' proves the vulnerability without breaking the site).

6. Test Data Setup

  1. Plugin Installation: Ensure Sprout Invoices <= 20.8.8 is installed and activated.
  2. Initial State: Verify the current currency setting via CLI:
    wp option get si_settings (The settings are often stored in a serialized array).
  3. Shortcode Page: Create a page to expose any potential nonces:
    wp post create --post_type=page --post_status=publish --post_title="Nonce Page" --post_content='[sprout_invoice_lead]'

7. Expected Results

  • HTTP Response: The server returns a 200 OK or a JSON success message (e.g., {"success":true}).
  • Effect: The si_settings option in the wp_options table is updated with the attacker-supplied value.

8. Verification Steps

  1. Database Check: Use WP-CLI to inspect the updated settings:
    wp option get si_settings
  2. Value Check: Confirm that the site_currency (or equivalent key used in the payload) now reflects the value EVIL.
  3. Log Check: (Optional) Check the WordPress debug log for unauthorized calls if logging is enabled.

9. Alternative Approaches

If si_save_settings is not the vulnerable action:

  • Search for other Nopriv Actions:
    grep -r "wp_ajax_nopriv_" /var/www/html/wp-content/plugins/sprout-invoices/
  • Target Inbound Leads: Attempt to bypass authorization on the si_process_lead action to inject malicious lead data.
  • Target Payment Status: Look for actions like si_update_payment_status which might allow marking invoices as paid without actual payment.
  • Bypass Nonce: If check_ajax_referer is called with die = false or if the return value is not checked, omit the nonce and see if the action still succeeds.

Check if your site is affected.

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