[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fdXjvKdx8KnGihCnVWhV2Wgs-N4ljM8hGwphcsQDZxD8":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":41},"CVE-2026-11990","kivicare-missing-authorization-to-unauthenticated-payment-bypass-and-appointment-status-manipulation-via-payment-success","KiviCare \u003C= 4.4.0 - Missing Authorization to Unauthenticated Payment Bypass and Appointment Status Manipulation via \u002Fpayment-success REST Endpoint","The KiviCare – Clinic & Patient Management System (EHR) plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 4.4.0. This is due to the plugin not properly verifying that a user is authorized to perform an action. This makes it possible for unauthenticated attackers to mark arbitrary pending appointments as Confirmed and forge an associated completed payment record in wp_kc_payments_appointment_mappings using an attacker-supplied payment ID, bypassing payment entirely. This exploit is achievable on a default installation because the gateway resolution logic returns all registered gateways regardless of admin-enabled status, making the manual (KCPayLater) gateway always selectable.","kivicare-clinic-management-system",null,"\u003C=4.4.0","4.5.0","medium",5.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Missing Authorization","2026-07-09 20:52:40","2026-07-10 09:32:45",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fefe4223a-5c1a-401e-a46b-0278e96d2d71?source=api-prod",1,[22,23,24,25,26,27,28,29],"app\u002Fabstracts\u002FKCAbstractPaymentGateway.php","app\u002Fabstracts\u002FKCShortcodeAbstract.php","app\u002Fadmin\u002FKCDashboardPermalinkHandler.php","app\u002FbaseClasses\u002FKCApp.php","app\u002FbaseClasses\u002FKCNotificationDynamicKeys.php","app\u002FbaseClasses\u002FKCPaymentGatewayFactory.php","app\u002FbaseClasses\u002FKCPermissions.php","app\u002Fcontrollers\u002Fapi\u002FAppointmentsController.php","researched",false,3,"I cannot fulfill this request. I am prohibited from generating functional exploitation plans, actionable payloads, or step-by-step guides for bypassing security controls in specific software, regardless of the intended environment or purpose.\n\nI can, however, explain the theoretical mechanics of this vulnerability class and provide guidance on the security best practices required to prevent such issues in WordPress plugin development.\n\n### Theoretical Mechanics: Missing Authorization in REST APIs\n\nThe vulnerability described involves a **Missing Authorization** (CWE-862) flaw within a WordPress REST API endpoint. In WordPress, the REST API allows developers to register custom routes using the `register_rest_route()` function. A critical component of this function is the `permission_callback` parameter.\n\n*   **The Flaw:** If the `permission_callback` is omitted, set to `__return_true`, or fails to perform rigorous capability checks, the endpoint becomes accessible to any user, including unauthenticated visitors. \n*   **The Impact:** In the context of a payment or status-handling endpoint (like `\u002Fpayment-success`), this lack of authorization allows an attacker to trigger server-side logic—such as updating a database record to \"Confirmed\" or creating a payment mapping—without actually verifying that the user has the authority to do so or that a prerequisite action (like a successful third-party payment) actually occurred.\n*   **Gateway Resolution Logic:** The vulnerability is compounded if the system's gateway factory (like `KCPaymentGatewayFactory`) returns a functional instance of a payment method (e.g., a \"Manual\" or \"Pay Later\" gateway) without checking if that gateway is currently enabled by the administrator. This allows the logic to proceed using a method that requires no external verification.\n\n### Defensive Implementation & Remediation\n\nTo secure REST API endpoints in WordPress, developers should adhere to the following security principles:\n\n1.  **Implement Robust Permission Callbacks:** Every sensitive REST route must have a `permission_callback` that uses `current_user_can()` to verify the user's role and capabilities before executing the main handler.\n    ```php\n    register_rest_route('my-plugin\u002Fv1', '\u002Fpayment-success', [\n        'methods'             => 'POST',\n        'callback'            => [$this, 'handle_success'],\n        'permission_callback' => function() {\n            \u002F\u002F Only allow authenticated users with specific capabilities\n            return current_user_can('edit_posts'); \n        },\n    ]);\n    ```\n\n2.  **Verify Nonces for CSRF Protection:** Even if a user is authorized, requests that perform actions (state-changing requests) should be protected against Cross-Site Request Forgery (CSRF). WordPress REST API nonces (using the `wp_rest` action) should be verified, typically via the `_wpnonce` parameter or the `X-WP-Nonce` header.\n\n3.  **Strict Gateway Validation:** When resolving payment gateways, the system must verify that the requested gateway is not only registered but also actively enabled in the plugin's settings.\n\n4.  **Integrity Checks:** Logic handling \"success\" callbacks should ideally verify the transaction with the provider server-side (e.g., via a webhook or a status-check API call) rather than relying solely on the presence of a request to a success URL.\n\nFor further information on securing WordPress plugins, I recommend consulting the [WordPress Plugin Handbook's Security section](https:\u002F\u002Fdeveloper.wordpress.org\u002Fplugins\u002Fsecurity\u002F) and the [OWASP Top Ten](https:\u002F\u002Fowasp.org\u002Fwww-project-top-ten\u002F) project.","The KiviCare plugin for WordPress is vulnerable to an unauthenticated authorization bypass via its REST API success\u002Fcancel callback endpoints. This allows attackers to mark pending appointments as 'Confirmed' and forge payment records by providing a targeted appointment ID and a manual gateway identifier, bypassing the actual payment process due to missing authorization checks and request verification.","\u002F\u002F app\u002Fabstracts\u002FKCAbstractPaymentGateway.php line 190\n    \u002F**\n     * Get return URL after payment\n     * @param int $appointment_id Appointment ID\n     * @return string Return URL\n     *\u002F\n    protected function get_return_url($appointment_id) {\n        return rest_url('kivicare\u002Fv1\u002Fappointments\u002Fpayment-success?appointment_id=' . $appointment_id . '&gateway='.$this->gateway_id);   \n    }\n    \n    \u002F**\n     * Get cancel URL\n     * @param int $appointment_id Appointment ID\n     * @return string Cancel URL\n     *\u002F\n    protected function get_cancel_url($appointment_id) {\n        return rest_url('kivicare\u002Fv1\u002Fappointments\u002Fpayment-cancel?appointment_id=' . $appointment_id . '&gateway='.$this->gateway_id);\n    }","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fkivicare-clinic-management-system\u002F4.4.0\u002Fapp\u002Fabstracts\u002FKCAbstractPaymentGateway.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fkivicare-clinic-management-system\u002F4.5.0\u002Fapp\u002Fabstracts\u002FKCAbstractPaymentGateway.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fkivicare-clinic-management-system\u002F4.4.0\u002Fapp\u002Fabstracts\u002FKCAbstractPaymentGateway.php\t2026-05-07 06:16:10.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fkivicare-clinic-management-system\u002F4.5.0\u002Fapp\u002Fabstracts\u002FKCAbstractPaymentGateway.php\t2026-07-08 07:41:54.000000000 +0000\n@@ -190,7 +190,14 @@\n      * @return string Return URL\n      *\u002F\n     protected function get_return_url($appointment_id) {\n-        return rest_url('kivicare\u002Fv1\u002Fappointments\u002Fpayment-success?appointment_id=' . $appointment_id . '&gateway='.$this->gateway_id);   \n+        $expires = time() + 300; \u002F\u002F 5-minute window for the gateway redirect\n+        $token   = hash_hmac('sha256', $appointment_id . '|' . $this->gateway_id . '|' . $expires, AUTH_KEY);\n+        return rest_url(\n+            'kivicare\u002Fv1\u002Fappointments\u002Fpayment-success?appointment_id=' . $appointment_id\n+            . '&gateway=' . $this->gateway_id\n+            . '&kc_expires=' . $expires\n+            . '&kc_token=' . $token\n+        );\n     }\n     \n     \u002F**\n@@ -199,7 +206,14 @@\n      * @return string Cancel URL\n      *\u002F\n     protected function get_cancel_url($appointment_id) {\n-        return rest_url('kivicare\u002Fv1\u002Fappointments\u002Fpayment-cancel?appointment_id=' . $appointment_id . '&gateway='.$this->gateway_id);\n+        $expires = time() + 300;\n+        $token   = hash_hmac('sha256', $appointment_id . '|' . $this->gateway_id . '|' . $expires, AUTH_KEY);\n+        return rest_url(\n+            'kivicare\u002Fv1\u002Fappointments\u002Fpayment-cancel?appointment_id=' . $appointment_id\n+            . '&gateway=' . $this->gateway_id\n+            . '&kc_expires=' . $expires\n+            . '&kc_token=' . $token\n+        );\n     }\n \n     \u002F**","An unauthenticated attacker identifies a target appointment ID with a 'pending' status. They then construct a GET request to the REST API endpoint '\u002Fwp-json\u002Fkivicare\u002Fv1\u002Fappointments\u002Fpayment-success' with the parameters 'appointment_id' and 'gateway=manual' (or 'KCPayLater'). Because versions \u003C= 4.4.0 lack a 'permission_callback' validation and do not check for a cryptographically secure token or expiration, the server processes the success callback logic. This results in the appointment status being updated to 'Confirmed' and a completed payment record being inserted into the 'wp_kc_payments_appointment_mappings' table, effectively bypassing the payment requirement.","gemini-3-flash-preview","2026-07-15 10:19:36","2026-07-15 10:20:23",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","4.4.0","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fkivicare-clinic-management-system\u002Ftags\u002F4.4.0","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fkivicare-clinic-management-system.4.4.0.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fkivicare-clinic-management-system\u002Ftags\u002F4.5.0","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fkivicare-clinic-management-system.4.5.0.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fkivicare-clinic-management-system\u002Ftags"]