CVE-2026-24999

Alma <= 5.16.1 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
5.16.2
Patched in
111d
Time to patch

Description

The Alma – Pay in installments or later for WooCommerce plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 5.16.1. This makes it possible for unauthenticated attackers to perform an unauthorized action.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=5.16.1
PublishedJanuary 14, 2026
Last updatedMay 4, 2026

What Changed in the Fix

Changes introduced in v5.16.2

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-24999 (Alma Payment Gateway) ## 1. Vulnerability Summary The **Alma – Pay in installments or later for WooCommerce** plugin (versions <= 5.16.1) contains a missing authorization vulnerability. Specifically, the plugin registers AJAX handlers that perform stat…

Show full research plan

Exploitation Research Plan - CVE-2026-24999 (Alma Payment Gateway)

1. Vulnerability Summary

The Alma – Pay in installments or later for WooCommerce plugin (versions <= 5.16.1) contains a missing authorization vulnerability. Specifically, the plugin registers AJAX handlers that perform state-changing actions (such as order cancellation) via wp_ajax_nopriv_ hooks without implementing proper capability checks or verifying that the requester owns the resource (e.g., the order). This allows unauthenticated attackers to perform unauthorized actions, most notably cancelling arbitrary WooCommerce orders.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: alma_cancel_order_in_page (identified from assets/js/alma-checkout-in-page.js)
  • HTTP Method: POST
  • Parameters:
    • action: alma_cancel_order_in_page
    • order_id: The WooCommerce order ID to be cancelled.
  • Authentication: None (unauthenticated).
  • Preconditions: A WooCommerce order must exist in the system.

3. Code Flow

  1. The client-side script assets/js/alma-checkout-in-page.js defines a function cancel_order(orderId).
  2. This function triggers a POST request to admin-ajax.php with action: 'alma_cancel_order_in_page'.
  3. The plugin's server-side logic (likely within the AlmaPlugin class or a service class like AlmaBusinessEventService) registers this action using add_action('wp_ajax_nopriv_alma_cancel_order_in_page', ...).
  4. The handler function executes. Because the vulnerability is "Missing Authorization," it fails to check:
    • If the user is logged in.
    • If the user has the edit_shop_orders capability.
    • If the order ID provided belongs to the current session/user.
  5. The handler proceeds to call WooCommerce methods (e.g., $order->update_status('cancelled')) based solely on the user-provided order_id.

4. Nonce Acquisition Strategy

Based on assets/js/alma-checkout-in-page.js, the cancel_order function does not appear to include a nonce in its data payload:

// From assets/js/alma-checkout-in-page.js
function cancel_order(orderId)
{
    var data = {
        'action': 'alma_cancel_order_in_page',
        'order_id': orderId
    };

    jQuery.post( ajax_object.ajax_url, data )
}

If the handler does verify a nonce (e.g., using check_ajax_referer), it would likely be localized in the ajax_object variable.

Acquisition Steps (if needed):

  1. The script is likely enqueued on the WooCommerce Checkout page.
  2. Navigate to the checkout page: browser_navigate("/checkout/").
  3. Execute JS to find the nonce: browser_eval("window.ajax_object?.nonce").
  4. If the handler is truly vulnerable to unauthenticated "unauthorized access," it likely either lacks the nonce check entirely or uses a generic, publicly accessible nonce.

5. Exploitation Strategy

The goal is to cancel a legitimate WooCommerce order as an unauthenticated attacker.

Step 1: Target Identification

Identify a valid Order ID (Post ID). In a real attack, these are often sequential or can be guessed.

Step 2: Malicious Request

Send a POST request to the AJAX endpoint.

Request Details:

  • URL: http://[TARGET]/wp-admin/admin-ajax.php
  • Content-Type: application/x-www-form-urlencoded
  • Body: action=alma_cancel_order_in_page&order_id=[TARGET_ORDER_ID]

Step 3: Secondary Actions

Other actions found in assets/js/alma-checkout-in-page.js should also be tested for unauthorized access:

  • alma_do_checkout_in_page: May allow unauthorized creation/manipulation of payment intents.
  • alma_return_checkout_in_page: May allow manipulation of the checkout return flow.

6. Test Data Setup

  1. Install WooCommerce and the Alma plugin (v5.16.1).
  2. Create a Product: wp post create --post_type=product --post_title="Test Product" --post_status=publish.
  3. Generate an Order:
    # Create an order for a guest user
    ORDER_ID=$(wp wc shop_order create --user=0 --customer_id=0 --status=pending --porcelain)
    echo "Created Order ID: $ORDER_ID"
    
  4. Configure Alma: Ensure the plugin is active (Alma API keys are not strictly necessary for the AJAX handler to exist, but the plugin must be enabled as a gateway).

7. Expected Results

  • The server should return a 200 OK or a JSON success response (e.g., {"success": true}).
  • The WooCommerce order status for the targeted ORDER_ID should change from pending (or processing) to cancelled.

8. Verification Steps

  1. Check Order Status via WP-CLI:
    wp wc shop_order get [ORDER_ID] --fields=status
    
    Successful exploit: The status should be cancelled.
  2. Check Order Notes:
    wp post get [ORDER_ID] --field=post_excerpt
    # Or check comments (WC Order Notes)
    wp comment list --post_id=[ORDER_ID]
    
    Check if a note was added stating the order was cancelled via Alma.

9. Alternative Approaches

If alma_cancel_order_in_page requires a nonce that is strictly tied to a specific session:

  1. Test alma_do_checkout_in_page. This action takes fields (serialized form). Attempt to pass a different order_id or manipulate order data during the "in-page" checkout creation process.
  2. If the vulnerability lies in alma_return_checkout_in_page, attempt to call it with a payment_id or order_id to trick the system into thinking a payment was successful or needs state reconciliation.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Alma plugin for WooCommerce (<= 5.16.1) fails to perform authorization, ownership, or nonce checks on several AJAX handlers, including the one responsible for order cancellation. This allows unauthenticated attackers to cancel arbitrary WooCommerce orders by providing a valid order ID to the admin-ajax.php endpoint.

Vulnerable Code

// assets/js/alma-checkout-in-page.js

function cancel_order(orderId)
{
    var data = {
        'action': 'alma_cancel_order_in_page',
        'order_id': orderId
    };

    jQuery.post( ajax_object.ajax_url, data )
}

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/alma-gateway-for-woocommerce/5.16.1/assets/js/alma-checkout-in-page.js	2024-12-12 15:40:18.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/alma-gateway-for-woocommerce/5.16.2/assets/js/alma-checkout-in-page.js	2026-01-29 13:42:24.000000000 +0000
@@ -131,15 +131,17 @@
 								'alma_fee_plan_in_page': feePlanChecked
 							};
 
-							paymentId = response.data.payment_id;
-							orderId   = response.data.order_id;
+							let paymentId = response.data.payment_id;
+							let orderId   = response.data.order_id;
+                            let orderKey   = response.data.order_key;
+                            let nonce = ajax_object.nonce;
 
-							// Start the payment.
+							// Start the payment.
 							inPage.startPayment(
 								{
 									paymentId:paymentId,
 									onUserCloseModal: () => {
-										cancel_order( orderId );
+										cancel_order( orderId, orderKey, nonce );
 										$( '.alma-loader-wrapper' ).remove();
 									}
 								}
@@ -162,11 +164,13 @@
 		$( "body" ).append( "<div class='alma-loader-wrapper'>" + loading + "</div>" );
 	}
 
-	function cancel_order(orderId)
+	function cancel_order(orderId, orderKey, nonce)
 	{
 		var data = {
 			'action': 'alma_cancel_order_in_page',
-			'order_id': orderId
+			'order_id': orderId,
+            'order_key': orderKey,
+            'nonce': nonce
 		};
 
 		jQuery.post( ajax_object.ajax_url, data )

Exploit Outline

The exploit involves a direct unauthenticated request to the WordPress AJAX endpoint. 1. Identify a target WooCommerce Order ID. In many WordPress installations, these are incremental and easily enumerable. 2. Send a POST request to `/wp-admin/admin-ajax.php`. 3. Include the following parameters in the body: `action=alma_cancel_order_in_page` and `order_id=[TARGET_ORDER_ID]`. 4. Because the vulnerable versions do not check for a nonce, order key, or the current user's session, the server-side handler (registered via `wp_ajax_nopriv_alma_cancel_order_in_page`) will process the request and update the status of the specified order to 'cancelled'.

Check if your site is affected.

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