CVE-2026-8611

Klamra Paycal for Aspaclaria <= 1.1.4 - Insecure Direct Object Reference to Authenticated (Subscriber+) Sensitive Information Exposure via 'invoice_id' Parameter

mediumAuthorization Bypass Through User-Controlled Key
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
1.1.5
Patched in
1d
Time to patch

Description

The Klamra Paycal for Aspaclaria plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 1.1.4 via the 'invoice_id' parameter due to missing validation on a user controlled key. This makes it possible for authenticated attackers, with subscriber-level access and above, to download arbitrary customer invoices by enumerating sequential post IDs, exposing sensitive billing PII including full name, email address, phone number, order total, line items, and customer notes belonging to other customers.

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.1.4
PublishedJune 5, 2026
Last updatedJune 6, 2026

What Changed in the Fix

Changes introduced in v1.1.5

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Research Plan: CVE-2026-8611 - IDOR in Klamra Paycal for Aspaclaria ## 1. Vulnerability Summary The **Klamra Paycal for Aspaclaria** plugin (versions <= 1.1.4) is vulnerable to an **Insecure Direct Object Reference (IDOR)**. The vulnerability exists because the plugin fails to perform adequate au…

Show full research plan

Research Plan: CVE-2026-8611 - IDOR in Klamra Paycal for Aspaclaria

1. Vulnerability Summary

The Klamra Paycal for Aspaclaria plugin (versions <= 1.1.4) is vulnerable to an Insecure Direct Object Reference (IDOR). The vulnerability exists because the plugin fails to perform adequate authorization checks when a user requests a customer invoice via the invoice_id parameter. While the system may check if a user is authenticated (Subscriber level or higher), it does not verify if the requesting user owns the invoice or has the necessary administrative privileges to view arbitrary invoices. This allows any authenticated user to enumerate sequential Post IDs and download sensitive billing PII belonging to other customers.

2. Attack Vector Analysis

  • Endpoint: Likely wp-admin/admin-post.php (for downloads) or wp-admin/admin-ajax.php. Alternatively, it could be a custom handler on init.
  • Action Name: Likely paycal_download_invoice or paycal_view_invoice (inferred from plugin naming conventions).
  • Vulnerable Parameter: invoice_id (passed via GET or POST).
  • Authentication: Required (Subscriber role is sufficient).
  • Preconditions: The "Invoices" module must be active (controllable via licensing, but often bypassable or active in test environments).

3. Code Flow (Inferred)

  1. Entry Point: An authenticated user sends a request to a handler (e.g., admin-post.php?action=paycal_download_invoice&invoice_id=123).
  2. Authorization Check: The plugin calls a check like is_user_logged_in() or Access::enforce('invoices').
  3. Vulnerable Logic:
    • The handler retrieves the invoice_id from $_GET or $_POST.
    • It fetches the invoice object (likely a Custom Post Type) using get_post($invoice_id).
    • Crucial Missing Step: The code fails to compare the invoice's owner (e.g., post_author or a specific meta field like _customer_user) with the current user's ID (get_current_user_id()).
  4. Sink: The plugin outputs the invoice data (PII, order totals, etc.) to the browser.

4. Nonce Acquisition Strategy

Based on the description of "enumeration," it is highly probable that the endpoint either lacks a nonce check or uses a generic nonce available to all logged-in users.

If a nonce is required:

  1. Identify the Source: Search for where the plugin localizes script data for invoices.
    • grep -r "wp_localize_script" .
  2. Localized Variable: Look for keys like paycal_invoice_vars or paycal_admin.
  3. Acquisition:
    • Create a page with a PayCal shortcode if necessary: wp post create --post_type=page --post_status=publish --post_content='[paycal_invoices]'
    • Navigate to the dashboard or the created page as a Subscriber.
    • Use browser_eval to extract the nonce: window.paycal_vars?.download_nonce.

5. Exploitation Strategy

Step 1: Discover the Endpoint and CPT

First, identify the exact action name and the Custom Post Type (CPT) name for invoices.

# Find the CPT name
grep -r "register_post_type" .
# Find the handler for invoice_id
grep -r "invoice_id" .

Step 2: Test Data Setup

Create two users and an invoice belonging to the admin.

# Create a Subscriber (Attacker)
wp user create attacker attacker@example.com --role=subscriber --user_pass=password

# Create an Admin (Victim)
wp user create victim victim@example.com --role=administrator --user_pass=password

# Create a dummy "Invoice" post (assuming CPT is 'paycal_invoice')
# If the CPT name differs, adjust accordingly.
INVOICE_ID=$(wp post create --post_type=paycal_invoice --post_title="Victim Invoice #1001" --post_author=$(wp user get victim --field=ID) --porcelain)

# Add dummy PII to the invoice meta
wp post meta add $INVOICE_ID "_billing_first_name" "John"
wp post meta add $INVOICE_ID "_billing_last_name" "Doe"
wp post meta add $INVOICE_ID "_billing_email" "john.doe@private.com"

Step 3: Execute IDOR Attack

Using the http_request tool, log in as the Subscriber and attempt to access the Admin's invoice.

Action (Inferred): paycal_download_invoice
Request:

GET /wp-admin/admin-post.php?action=paycal_download_invoice&invoice_id=[INVOICE_ID] HTTP/1.1
Host: localhost:8080
Cookie: [Subscriber Cookies]

6. Test Data Setup (Detailed)

  1. Plugin Activation: Ensure the plugin is active.
  2. Licensing Gate: If Gate::has('invoices') returns false, the UI might be blocked, but the admin-post handler might still execute. If necessary, mock the license:
    wp option update paycal_license_data '{"valid":true,"modules":["invoices"],"expires_at":"2030-01-01"}'
    
  3. Target Content: Ensure the paycal_invoice (or correct CPT) exists with an ID identifiable via WP-CLI.

7. Expected Results

  • Successful Exploitation: The server returns a 200 OK response containing the details of the invoice created by the Admin (John Doe, email, etc.), despite the request being made by a Subscriber.
  • Vulnerability Confirmation: The response content matches the PII stored in the victim invoice.

8. Verification Steps

  1. Check the response body of the http_request for the strings: "John", "Doe", and "john.doe@private.com".
  2. Verify the ID of the invoice being viewed belongs to the Admin user:
    wp post get [INVOICE_ID] --field=post_author
    # Confirm this ID matches the Victim user ID, not the Attacker user ID.
    

9. Alternative Approaches

  • AJAX Endpoint: If admin-post.php is not the target, check wp-admin/admin-ajax.php?action=paycal_get_invoice_data&invoice_id=[ID].
  • Rest API: Check if the plugin registers a REST route in includes/Admin/class-rest.php (if exists) via register_rest_route.
  • Shortcode IDOR: Check if a shortcode like [paycal_invoice id="123"] renders private info on the frontend when accessed by a subscriber.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Klamra Paycal for Aspaclaria plugin for WordPress is vulnerable to an Insecure Direct Object Reference (IDOR) via the 'invoice_id' parameter in versions up to 1.1.4. This allows authenticated attackers with subscriber-level access to download arbitrary customer invoices by enumerating sequential post IDs, leading to the exposure of sensitive personal identifiable information (PII) and billing data.

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/klamra-paycal-for-aspaclaria/1.1.4/assets/admin.css /home/deploy/wp-safety.org/data/plugin-versions/klamra-paycal-for-aspaclaria/1.1.5/assets/admin.css
--- /home/deploy/wp-safety.org/data/plugin-versions/klamra-paycal-for-aspaclaria/1.1.4/assets/admin.css	2026-05-28 13:12:50.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/klamra-paycal-for-aspaclaria/1.1.5/assets/admin.css	2026-05-30 21:20:06.000000000 +0000
@@ -13,6 +13,261 @@
 
 .paycal-wrap{ color:var(--paycal-text); }
 
+.paycal-wrap .notice,
+.paycal-wrap div.notice,
+.paycal-wrap .notice p{
+  color:#111827 !important;
+}
+...
+diff -ru /home/deploy/wp-safety.org/data/plugin-versions/klamra-paycal-for-aspaclaria/1.1.4/includes/Admin/Page_Dashboard.php /home/deploy/wp-safety.org/data/plugin-versions/klamra-paycal-for-aspaclaria/1.1.5/includes/Admin/Page_Dashboard.php
+--- /home/deploy/wp-safety.org/data/plugin-versions/klamra-paycal-for-aspaclaria/1.1.4/includes/Admin/Page_Dashboard.php	2026-05-28 13:12:50.000000000 +0000
++++ /home/deploy/wp-safety.org/data/plugin-versions/klamra-paycal-for-aspaclaria/1.1.5/includes/Admin/Page_Dashboard.php	2026-05-30 21:20:06.000000000 +0000
+@@ -14,10 +14,13 @@
+     $data = LicenseStore::get();
+     $mods = array_values(array_filter((array) ($data['modules'] ?? [])));
+     $license_label = Gate::status_label();
+-    $license_active = strtolower((string) $license_label) !== 'no license';
++    $license_active = !empty($data['valid']);
++    $license_in_grace = $license_label === 'Grace period';
++    $license_display = $license_active || $license_in_grace ? $license_label : 'לא מחובר';
+ 
+     $bit_enabled = Gate::has('bit');
+-    $invoices_enabled = Gate::has('invoices');
++    $invoice_settings = get_option('paycal_invoice_settings', []);
++    $invoices_enabled = !is_array($invoice_settings) || !isset($invoice_settings['enabled']) || (string) $invoice_settings['enabled'] === 'yes';
+ 
+     $bit_pending_count = 0;
+     if (class_exists('\\WooCommerce') && $bit_enabled && function_exists('wc_get_orders')) {
... (truncated)

Exploit Outline

1. Authenticate to the WordPress site with a user account possessing Subscriber-level privileges or higher. 2. Locate the invoice download endpoint, which typically handles requests via a parameter like 'invoice_id' (e.g., through an admin-post.php or admin-ajax.php action). 3. Send a request to the identified endpoint while providing an 'invoice_id' that belongs to another user's invoice. 4. Observe that the plugin responds with the full content of the requested invoice—including the customer's full name, email, phone number, and order details—because it fails to check if the current user owns the resource or has administrative rights.

Check if your site is affected.

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