Klamra Paycal for Aspaclaria <= 1.1.4 - Insecure Direct Object Reference to Authenticated (Subscriber+) Sensitive Information Exposure via 'invoice_id' Parameter
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:NTechnical Details
<=1.1.4What Changed in the Fix
Changes introduced in v1.1.5
Source Code
WordPress.org SVN# 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) orwp-admin/admin-ajax.php. Alternatively, it could be a custom handler oninit. - Action Name: Likely
paycal_download_invoiceorpaycal_view_invoice(inferred from plugin naming conventions). - Vulnerable Parameter:
invoice_id(passed viaGETorPOST). - 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)
- Entry Point: An authenticated user sends a request to a handler (e.g.,
admin-post.php?action=paycal_download_invoice&invoice_id=123). - Authorization Check: The plugin calls a check like
is_user_logged_in()orAccess::enforce('invoices'). - Vulnerable Logic:
- The handler retrieves the
invoice_idfrom$_GETor$_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_authoror a specific meta field like_customer_user) with the current user's ID (get_current_user_id()).
- The handler retrieves the
- 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:
- Identify the Source: Search for where the plugin localizes script data for invoices.
grep -r "wp_localize_script" .
- Localized Variable: Look for keys like
paycal_invoice_varsorpaycal_admin. - 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_evalto extract the nonce:window.paycal_vars?.download_nonce.
- Create a page with a PayCal shortcode if necessary:
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)
- Plugin Activation: Ensure the plugin is active.
- Licensing Gate: If
Gate::has('invoices')returns false, the UI might be blocked, but theadmin-posthandler might still execute. If necessary, mock the license:wp option update paycal_license_data '{"valid":true,"modules":["invoices"],"expires_at":"2030-01-01"}' - 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 OKresponse 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
victiminvoice.
8. Verification Steps
- Check the response body of the
http_requestfor the strings:"John","Doe", and"john.doe@private.com". - 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.phpis not the target, checkwp-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) viaregister_rest_route. - Shortcode IDOR: Check if a shortcode like
[paycal_invoice id="123"]renders private info on the frontend when accessed by a subscriber.
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
@@ -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 +@@ -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.