Sprout Invoices – Client Invoicing & Estimates <= 20.8.13 - Missing Authorization
Description
The Sprout Invoices – Client Invoicing & Estimates 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.13. 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
<=20.8.13What Changed in the Fix
Changes introduced in v20.8.14
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-57418 (Missing Authorization) ## 1. Vulnerability Summary The **Sprout Invoices – Client Invoicing & Estimates** plugin (version <= 20.8.13) is vulnerable to missing authorization in several AJAX handlers. Specifically, functions registered under the `wp_ajax_…
Show full research plan
Exploitation Research Plan: CVE-2026-57418 (Missing Authorization)
1. Vulnerability Summary
The Sprout Invoices – Client Invoicing & Estimates plugin (version <= 20.8.13) is vulnerable to missing authorization in several AJAX handlers. Specifically, functions registered under the wp_ajax_ prefix in SI_Settings_API and SI_Estimates/SI_Invoices fail to verify the user's capability (authorization) before performing actions. This allows an authenticated user with Subscriber-level access to perform unauthorized actions, such as modifying plugin settings or sending arbitrary notifications.
2. Attack Vector Analysis
- Target Endpoint:
/wp-admin/admin-ajax.php - Vulnerable Action:
si_gtag_option_action(and potentiallysi_stripe_option_actionorsa_send_est_notification). - Required Authentication: Subscriber or higher.
- Payload Parameter:
option(forsi_gtag_option_action) orsa_metabox_recipients(for notification spam). - Security Check: The functions verify a nonce (usually passed as
securityornonce) but do not check for themanage_sprout_invoices_optionsoredit_sprout_invoicescapabilities.
3. Code Flow
- Registration: In
controllers/admin/Settings_API.php,
Summary
The Sprout Invoices plugin for WordPress is vulnerable to unauthorized access because multiple AJAX and REST API handlers fail to perform capability checks. Authenticated users, including those with subscriber-level permissions, can perform unauthorized actions such as sending arbitrary notifications for invoices and estimates or managing plugin add-ons.
Vulnerable Code
// controllers/estimates/Estimates.php:127 public static function maybe_send_notification() { // ... if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['sa_send_metabox_notification_nonce'] ) ), SI_Controller::NONCE ) ) { self::ajax_fail( 'Not going to fall for it!' ); } if ( ! isset( $_REQUEST['sa_send_metabox_doc_id'] ) ) { self::ajax_fail( 'Forget something (id)?' ); } if ( get_post_type( sanitize_text_field( wp_unslash( $_REQUEST['sa_send_metabox_doc_id'] ) ) ) !== SI_Estimate::POST_TYPE ) { return; } $recipients = ( isset( $_REQUEST['sa_metabox_recipients'] ) ) ? array_map( 'sanitize_text_field', ( wp_unslash( $_REQUEST['sa_metabox_recipients'] ) ) ) : array(); --- // controllers/invoices/Invoices.php:115 public static function maybe_send_notification() { // ... if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['sa_send_metabox_notification_nonce'] ) ), SI_Controller::NONCE ) ) { self::ajax_fail( 'Not going to fall for it!' ); } if ( ! isset( $_REQUEST['sa_send_metabox_doc_id'] ) ) { self::ajax_fail( 'Forget something (id)?' ); } if ( get_post_type( sanitize_text_field( wp_unslash( $_REQUEST['sa_send_metabox_doc_id'] ) ) ) !== SI_Invoice::POST_TYPE ) { return; } $recipients = ( isset( $_REQUEST['sa_metabox_recipients'] ) ) ? array_map( 'sanitize_text_field', ( wp_unslash( $_REQUEST['sa_metabox_recipients'] ) ) ) : array(); --- // controllers/admin/Settings_API.php:673 'callback' => function () { // phpcs:disable WordPress.Security.NonceVerification.Missing -- WordPress REST API validates authentication via X-WP-Nonce header; permission_callback enforces capability $_POST = stripslashes_deep( $_POST ); if ( isset( $_POST['activate'] ) ) { SA_Addons::activate_addon( sanitize_text_field( wp_unslash( $_POST['activate'] ) ) ); } if ( isset( $_POST['deactivate'] ) ) { SA_Addons::deactivate_addon( sanitize_text_field( wp_unslash( $_POST['deactivate'] ) ) ); }
Security Fix
@@ -141,10 +141,33 @@ if ( ! isset( $_REQUEST['sa_send_metabox_doc_id'] ) ) { self::ajax_fail( 'Forget something (id)?' ); } - if ( get_post_type( sanitize_text_field( wp_unslash( $_REQUEST['sa_send_metabox_doc_id'] ) ) ) !== SI_Estimate::POST_TYPE ) { + $doc_id = absint( wp_unslash( $_REQUEST['sa_send_metabox_doc_id'] ) ); + $post_type = get_post_type( $doc_id ); + + if ( SI_Invoice::POST_TYPE === $post_type ) { return; } + if ( SI_Estimate::POST_TYPE !== $post_type ) { + self::ajax_fail( 'Not an invoice or estimate.' ); + } + + if ( ! current_user_can( 'edit_post', $doc_id ) ) { + self::ajax_fail( 'You do not have permission to send this notification.' ); + } + @@ -125,10 +125,33 @@ self::ajax_fail( 'Forget something (id)?' ); } - if ( get_post_type( sanitize_text_field( wp_unslash( $_REQUEST['sa_send_metabox_doc_id'] ) ) ) !== SI_Invoice::POST_TYPE ) { + $doc_id = absint( wp_unslash( $_REQUEST['sa_send_metabox_doc_id'] ) ); + $post_type = get_post_type( $doc_id ); + + if ( SI_Estimate::POST_TYPE === $post_type ) { return; } + if ( SI_Invoice::POST_TYPE !== $post_type ) { + self::ajax_fail( 'Not an invoice or estimate.' ); + } + + if ( ! current_user_can( 'edit_post', $doc_id ) ) { + self::ajax_fail( 'You do not have permission to send this notification.' ); + }
Exploit Outline
To exploit this vulnerability, an attacker first authenticates with a low-privileged account (such as a Subscriber). They then extract the global nonce from the frontend via the `si_js_object.security` variable, which is exposed to all logged-in users. Using this nonce, the attacker can make POST requests to `/wp-admin/admin-ajax.php` with the action `sa_send_est_notification`. By providing an arbitrary invoice or estimate ID in the `sa_send_metabox_doc_id` parameter and a list of target emails in `sa_metabox_recipients[]`, the attacker can trigger the plugin to send official invoice/estimate notifications to any address, potentially leading to information disclosure or spam.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.