REPORT / 01
Analysis Report · Folder Analysis cache/ipaymu-for-woocommerce_2.0.2 → cache/ipaymu-for-woocommerce_2.0.3 — CVE-2026-0656
Shared security patch analysis results
02 ·
Lifecycle actions
cancel · resume · skip · regenerate
03 ·
Share this analysis
copy link · embed report
03 ·
CVE Security Analysis & Writeups
ai-generated · per cve
Comprehensive security analysis generated by AI for each confirmed CVE match. Click on a CVE to view the detailed writeup including vulnerability background, technical details, patch analysis, and PoC guide.
CVE-2026-0656
NVD
AI-Generated Analysis
05 ·
Findings
filter · search · paginate
Showing 0 to 0 of 0 results
gateway.php
AI: 3 vulnerabilities
2 false positives, 1 true positive
CVE-2026-0656
--- cache/ipaymu-for-woocommerce_2.0.2/gateway.php 2026-01-07 00:37:46.920082368 +0000+++ cache/ipaymu-for-woocommerce_2.0.3/gateway.php 2026-01-07 00:38:13.549733095 +0000@@ -1,11 +1,11 @@ <?php -if ( ! defined( 'ABSPATH' ) ) {- exit;+if (!defined("ABSPATH")) {+ exit(); } -class Ipaymu_WC_Gateway extends WC_Payment_Gateway {-+class Ipaymu_WC_Gateway extends WC_Payment_Gateway+{ public $id; public $method_title; public $method_description;@@ -22,215 +22,291 @@ public $secret; public $completed_payment; - public function __construct() {-- $this->id = 'ipaymu';- $this->method_title = 'iPaymu Payment';- $this->method_description = 'Pembayaran Virtual Account, QRIS, Alfamart/Indomaret, Direct Debit, Kartu Kredit, dan COD.';- $this->has_fields = false;- $this->icon = plugins_url( '/ipaymu_badge.png', __FILE__ );-- $default_return_url = home_url( '/checkout/order-received/' );- $this->redirect_url = add_query_arg( 'wc-api', 'Ipaymu_WC_Gateway', home_url( '/' ) );+ public function __construct()+ {+ $this->id = "ipaymu";+ $this->method_title = "iPaymu Payment";+ $this->method_description =+ "Pembayaran Virtual Account, QRIS, Alfamart/Indomaret, Direct Debit, Kartu Kredit, dan COD.";+ $this->has_fields = false;+ $this->icon = plugins_url("/ipaymu_badge.png", __FILE__);++ $default_return_url = home_url("/checkout/order-received/");+ $this->redirect_url = add_query_arg(+ "wc-api",+ "Ipaymu_WC_Gateway",+ home_url("/")+ ); // Load the form fields and settings. $this->init_form_fields(); $this->init_settings(); // User settings.- $this->enabled = $this->get_option( 'enabled' );- $this->auto_redirect = $this->get_option( 'auto_redirect', '60' );- $this->return_url = $this->get_option( 'return_url', $default_return_url );- $this->expired_time = $this->get_option( 'expired_time', 24 );- $this->title = $this->get_option( 'title', 'Pembayaran iPaymu' );- $this->description = $this->get_option( 'description', 'Pembayaran melalui Virtual Account, QRIS, Alfamart/Indomaret, Direct Debit, Kartu Kredit, dan COD.' );-- if ( 'yes' === $this->get_option( 'testmode', 'yes' ) ) {- $this->url = 'https://sandbox.ipaymu.com/api/v2/payment';- $this->va = $this->get_option( 'sandbox_va' );- $this->secret = $this->get_option( 'sandbox_key' );+ $this->enabled = $this->get_option("enabled");+ $this->auto_redirect = $this->get_option("auto_redirect", "60");+ $this->return_url = $this->get_option(+ "return_url",+ $default_return_url+ );+ $this->expired_time = $this->get_option("expired_time", 24);+ $this->title = $this->get_option("title", "Pembayaran iPaymu");+ $this->description = $this->get_option(+ "description",+ "Pembayaran melalui Virtual Account, QRIS, Alfamart/Indomaret, Direct Debit, Kartu Kredit, dan COD."+ );++ if ("yes" === $this->get_option("testmode", "yes")) {+ $this->url = "https://sandbox.ipaymu.com/api/v2/payment";+ $this->va = $this->get_option("sandbox_va");+ $this->secret = $this->get_option("sandbox_key"); } else {- $this->url = 'https://my.ipaymu.com/api/v2/payment';- $this->va = $this->get_option( 'production_va' );- $this->secret = $this->get_option( 'production_key' );+ $this->url = "https://my.ipaymu.com/api/v2/payment";+ $this->va = $this->get_option("production_va");+ $this->secret = $this->get_option("production_key"); } - $this->completed_payment = ( 'yes' === $this->get_option( 'completed_payment', 'no' ) ) ? 'yes' : 'no';+ $this->completed_payment =+ "yes" === $this->get_option("completed_payment", "no")+ ? "yes"+ : "no"; // Hooks.- add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );+ add_action("woocommerce_update_options_payment_gateways_" . $this->id, [+ $this,+ "process_admin_options",+ ]); // Register both the new and legacy API hooks so existing webhook // configurations continue to work after the class rename.- add_action( 'woocommerce_api_ipaymu_wc_gateway', array( $this, 'check_ipaymu_response' ) );- add_action( 'woocommerce_api_wc_gateway_ipaymu', array( $this, 'check_ipaymu_response' ) );+ add_action("woocommerce_api_ipaymu_wc_gateway", [+ $this,+ "check_ipaymu_response",+ ]);+ add_action("woocommerce_api_wc_gateway_ipaymu", [+ $this,+ "check_ipaymu_response",+ ]); } /** * Admin options fields. */- public function init_form_fields() {-- $this->form_fields = array(- 'enabled' => array(- 'title' => __( 'Enable/Disable', 'ipaymu-for-woocommerce' ),- 'label' => 'Enable iPaymu Payment Gateway',- 'type' => 'checkbox',- 'description' => '',- 'default' => 'yes',- ),- 'title' => array(- 'title' => __( 'Title', 'ipaymu-for-woocommerce' ),- 'type' => 'text',- 'description' => 'Nama Metode Pembayaran',- 'default' => 'Pembayaran iPaymu',- 'desc_tip' => true,- ),- 'description' => array(- 'title' => __( 'Description', 'ipaymu-for-woocommerce' ),- 'type' => 'textarea',- 'description' => 'Deskripsi Metode Pembayaran',- 'default' => 'Pembayaran melalui Virtual Account, QRIS, Alfamart / Indomaret, Direct Debit, Kartu Kredit, COD, dan lainnya ',- ),- 'testmode' => array(- 'title' => __( 'Mode Test/Sandbox', 'ipaymu-for-woocommerce' ),- 'label' => 'Enable Test Mode / Sandbox',- 'type' => 'checkbox',- 'description' => '<small>Mode Sandbox/Development digunakan untuk testing transaksi, jika mengaktifkan mode sandbox Anda harus memasukan API Key Sandbox (<a href="https://sandbox.ipaymu.com/integration" target="_blank">dapatkan API Key Sandbox</a>)</small>',- 'default' => 'yes',- ),- 'completed_payment' => array(- 'title' => __( 'Status Completed After Payment', 'ipaymu-for-woocommerce' ),- 'label' => 'Status Completed After Payment',- 'type' => 'checkbox',- 'description' => '<small>Jika diaktifkan status order menjadi selesai setelah customer melakukan pembayaran. (Default: Processing)</small>',- 'default' => 'no',- ),- 'sandbox_va' => array(- 'title' => 'VA Sandbox',- 'type' => 'text',- 'description' => '<small>Dapatkan VA Sandbox <a href="https://sandbox.ipaymu.com/integration" target="_blank">di sini</a></small>',- 'default' => '',- ),- 'sandbox_key' => array(- 'title' => 'API Key Sandbox',- 'type' => 'password',- 'description' => '<small>Dapatkan API Key Sandbox <a href="https://sandbox.ipaymu.com/integration" target="_blank">di sini</a></small>',- 'default' => '',- ),- 'production_va' => array(- 'title' => 'VA Live/Production',- 'type' => 'text',- 'description' => '<small>Dapatkan VA Production <a href="https://my.ipaymu.com/integration" target="_blank">di sini</a></small>',- 'default' => '',- ),- 'production_key' => array(- 'title' => 'API Key Live/Production',- 'type' => 'password',- 'description' => '<small>Dapatkan API Key Production <a href="https://my.ipaymu.com/integration" target="_blank">di sini</a></small>',- 'default' => '',- ),- 'auto_redirect' => array(- 'title' => __( 'Waktu redirect ke Thank You Page (time of redirect to Thank You Page in seconds)', 'ipaymu-for-woocommerce' ),- 'type' => 'text',- 'description' => __( '<small>Dalam hitungan detik. Masukkan -1 untuk langsung redirect ke halaman Anda</small>.', 'ipaymu-for-woocommerce' ),- 'default' => '60',- ),- 'return_url' => array(- 'title' => __( 'Url Thank You Page', 'ipaymu-for-woocommerce' ),- 'type' => 'text',- 'description' => __( '<small>Link halaman setelah pembeli melakukan checkout pesanan</small>.', 'ipaymu-for-woocommerce' ),- 'default' => home_url( '/checkout/order-received/' ),- ),- 'expired_time' => array(- 'title' => __( 'Expired kode pembayaran (expiry time of payment code)', 'ipaymu-for-woocommerce' ),- 'type' => 'text',- 'description' => __( '<small>Dalam hitungan jam (in hours)</small>.', 'ipaymu-for-woocommerce' ),- 'default' => '24',- ),- );+ public function init_form_fields()+ {+ $this->form_fields = [+ "enabled" => [+ "title" => __("Enable/Disable", "ipaymu-for-woocommerce"),+ "label" => "Enable iPaymu Payment Gateway",+ "type" => "checkbox",+ "description" => "",+ "default" => "yes",+ ],+ "title" => [+ "title" => __("Title", "ipaymu-for-woocommerce"),+ "type" => "text",+ "description" => "Nama Metode Pembayaran",+ "default" => "Pembayaran iPaymu",+ "desc_tip" => true,+ ],+ "description" => [+ "title" => __("Description", "ipaymu-for-woocommerce"),+ "type" => "textarea",+ "description" => "Deskripsi Metode Pembayaran",+ "default" =>+ "Pembayaran melalui Virtual Account, QRIS, Alfamart / Indomaret, Direct Debit, Kartu Kredit, COD, dan lainnya ",+ ],+ "testmode" => [+ "title" => __("Mode Test/Sandbox", "ipaymu-for-woocommerce"),+ "label" => "Enable Test Mode / Sandbox",+ "type" => "checkbox",+ "description" =>+ '<small>Mode Sandbox/Development digunakan untuk testing transaksi, jika mengaktifkan mode sandbox Anda harus memasukan API Key Sandbox (<a href="https://sandbox.ipaymu.com/integration" target="_blank">dapatkan API Key Sandbox</a>)</small>',+ "default" => "yes",+ ],+ "completed_payment" => [+ "title" => __(+ "Status Completed After Payment",+ "ipaymu-for-woocommerce"+ ),+ "label" => "Status Completed After Payment",+ "type" => "checkbox",+ "description" =>+ "<small>Jika diaktifkan status order menjadi selesai setelah customer melakukan pembayaran. (Default: Processing)</small>",+ "default" => "no",+ ],+ "sandbox_va" => [+ "title" => "VA Sandbox",+ "type" => "text",+ "description" =>+ '<small>Dapatkan VA Sandbox <a href="https://sandbox.ipaymu.com/integration" target="_blank">di sini</a></small>',+ "default" => "",+ ],+ "sandbox_key" => [+ "title" => "API Key Sandbox",+ "type" => "password",+ "description" =>+ '<small>Dapatkan API Key Sandbox <a href="https://sandbox.ipaymu.com/integration" target="_blank">di sini</a></small>',+ "default" => "",+ ],+ "production_va" => [+ "title" => "VA Live/Production",+ "type" => "text",+ "description" =>+ '<small>Dapatkan VA Production <a href="https://my.ipaymu.com/integration" target="_blank">di sini</a></small>',+ "default" => "",+ ],+ "production_key" => [+ "title" => "API Key Live/Production",+ "type" => "password",+ "description" =>+ '<small>Dapatkan API Key Production <a href="https://my.ipaymu.com/integration" target="_blank">di sini</a></small>',+ "default" => "",+ ],+ "auto_redirect" => [+ "title" => __(+ "Waktu redirect ke Thank You Page (time of redirect to Thank You Page in seconds)",+ "ipaymu-for-woocommerce"+ ),+ "type" => "text",+ "description" => __(+ "<small>Dalam hitungan detik. Masukkan -1 untuk langsung redirect ke halaman Anda</small>.",+ "ipaymu-for-woocommerce"+ ),+ "default" => "60",+ ],+ "return_url" => [+ "title" => __("Url Thank You Page", "ipaymu-for-woocommerce"),+ "type" => "text",+ "description" => __(+ "<small>Link halaman setelah pembeli melakukan checkout pesanan</small>.",+ "ipaymu-for-woocommerce"+ ),+ "default" => home_url("/checkout/order-received/"),+ ],+ "expired_time" => [+ "title" => __(+ "Expired kode pembayaran (expiry time of payment code)",+ "ipaymu-for-woocommerce"+ ),+ "type" => "text",+ "description" => __(+ "<small>Dalam hitungan jam (in hours)</small>.",+ "ipaymu-for-woocommerce"+ ),+ "default" => "24",+ ],+ ]; } /** * Process the payment and return the redirect URL. */- public function process_payment( $order_id ) {-- $order = wc_get_order( $order_id );-- $buyerName = trim( $order->get_billing_first_name() . ' ' . $order->get_billing_last_name() );+ public function process_payment($order_id)+ {+ $order = wc_get_order($order_id);++ $buyerName = trim(+ $order->get_billing_first_name() .+ " " .+ $order->get_billing_last_name()+ ); $buyerEmail = $order->get_billing_email(); $buyerPhone = $order->get_billing_phone(); - $notifyUrl = $this->redirect_url . '&id_order=' . $order_id . '¶m=notify&order_status=on-hold';- if ( 'yes' === $this->completed_payment ) {- $notifyUrl = $this->redirect_url . '&id_order=' . $order_id . '¶m=notify&order_status=completed';- }-- $body = array(- 'product' => array( 'Order #' . $order_id ),- 'qty' => array( 1 ),- 'price' => array( (float) $order->get_total() ),- 'buyerName' => ! empty( $buyerName ) ? $buyerName : null,- 'buyerPhone' => ! empty( $buyerPhone ) ? $buyerPhone : null,- 'buyerEmail' => ! empty( $buyerEmail ) ? $buyerEmail : null,- 'referenceId' => (string) $order_id,- 'returnUrl' => $this->return_url,- 'cancelUrl' => $this->redirect_url . '&id_order=' . $order_id . '¶m=cancel',- 'notifyUrl' => $notifyUrl,- 'expired' => (int) $this->expired_time,- 'expiredType' => 'hours',- );-- $bodyJson = wp_json_encode( $body, JSON_UNESCAPED_SLASHES );- $requestBody = strtolower( hash( 'sha256', $bodyJson ) );- $stringToSign = 'POST:' . $this->va . ':' . $requestBody . ':' . $this->secret;- $signature = hash_hmac( 'sha256', $stringToSign, $this->secret );-- $headers = array(- 'Accept' => 'application/json',- 'Content-Type' => 'application/json',- 'va' => $this->va,- 'signature' => $signature,- );-- $response_http = wp_remote_post(- $this->url,- array(- 'headers' => $headers,- 'body' => $bodyJson,- 'timeout' => 60,- )- );-- if ( is_wp_error( $response_http ) ) {- $err_safe = sanitize_text_field( $response_http->get_error_message() );+ $notifyUrl =+ $this->redirect_url .+ "&id_order=" .+ $order_id .+ "¶m=notify&order_status=on-hold";+ if ("yes" === $this->completed_payment) {+ $notifyUrl =+ $this->redirect_url .+ "&id_order=" .+ $order_id .+ "¶m=notify&order_status=completed";+ }++ $body = [+ "product" => ["Order #" . $order_id],+ "qty" => [1],+ "price" => [(float) $order->get_total()],+ "buyerName" => !empty($buyerName) ? $buyerName : null,+ "buyerPhone" => !empty($buyerPhone) ? $buyerPhone : null,+ "buyerEmail" => !empty($buyerEmail) ? $buyerEmail : null,+ "referenceId" => (string) $order_id,+ "returnUrl" => $this->return_url,+ "cancelUrl" =>+ $this->redirect_url .+ "&id_order=" .+ $order_id .+ "¶m=cancel",+ "notifyUrl" => $notifyUrl,+ "expired" => (int) $this->expired_time,+ "expiredType" => "hours",+ ];++ $bodyJson = wp_json_encode($body, JSON_UNESCAPED_SLASHES);+ $requestBody = strtolower(hash("sha256", $bodyJson));+ $stringToSign =+ "POST:" . $this->va . ":" . $requestBody . ":" . $this->secret;+ $signature = hash_hmac("sha256", $stringToSign, $this->secret);++ $headers = [+ "Accept" => "application/json",+ "Content-Type" => "application/json",+ "va" => $this->va,+ "signature" => $signature,+ ];++ $response_http = wp_remote_post($this->url, [+ "headers" => $headers,+ "body" => $bodyJson,+ "timeout" => 60,+ ]);++ if (is_wp_error($response_http)) {+ $err_safe = sanitize_text_field(+ $response_http->get_error_message()+ ); throw new Exception( sprintf( /* translators: %s: HTTP error message. */- esc_html__( 'Request failed: %s', 'ipaymu-for-woocommerce' ),- esc_html( $err_safe )+ esc_html__("Request failed: %s", "ipaymu-for-woocommerce"),+ esc_html($err_safe) ) ); } - $res = wp_remote_retrieve_body( $response_http );+ $res = wp_remote_retrieve_body($response_http); - if ( empty( $res ) ) {+ if (empty($res)) { throw new Exception(- esc_html__( 'Request failed: empty response from iPaymu. Please contact [email protected].', 'ipaymu-for-woocommerce' )+ esc_html__(+ "Request failed: empty response from iPaymu. Please contact [email protected].",+ "ipaymu-for-woocommerce"+ ) ); } - $response = json_decode( $res );+ $response = json_decode($res); - if ( empty( $response ) || empty( $response->Data ) || empty( $response->Data->Url ) ) {- $message = isset( $response->Message ) ? $response->Message : 'Unknown error';- $message_safe = sanitize_text_field( $message );+ if (+ empty($response) ||+ empty($response->Data) ||+ empty($response->Data->Url)+ ) {+ $message = isset($response->Message)+ ? $response->Message+ : "Unknown error";+ $message_safe = sanitize_text_field($message); throw new Exception( sprintf( /* translators: %s: error message from iPaymu API. */- esc_html__( 'Invalid request. Response iPaymu: %s', 'ipaymu-for-woocommerce' ),- esc_html( $message_safe )+ esc_html__(+ "Invalid request. Response iPaymu: %s",+ "ipaymu-for-woocommerce"+ ),+ esc_html($message_safe) ) ); }@@ -238,145 +314,421 @@ // Empty the cart. WC()->cart->empty_cart(); - return array(- 'result' => 'success',- 'redirect' => esc_url_raw( $response->Data->Url ),- );+ return [+ "result" => "success",+ "redirect" => esc_url_raw($response->Data->Url),+ ]; } /** * Handle callback / notify from iPaymu. */- public function check_ipaymu_response() {+ public function check_ipaymu_response()+ {+ // phpcs:disable WordPress.Security.NonceVerification.Recommended+ $order_id = isset($_REQUEST["id_order"])+ ? absint($_REQUEST["id_order"])+ : 0;+ $is_webhook_post =+ isset($_SERVER["REQUEST_METHOD"]) &&+ "POST" === $_SERVER["REQUEST_METHOD"];+ // phpcs:enable WordPress.Security.NonceVerification.Recommended++ $request_data = [];+ if ($is_webhook_post) {+ $request_data = $this->get_request_data_from_webhook();+ }++ // --- Handle Webhook POST Request (Server to Server) ---+ if ($is_webhook_post && !empty($request_data)) {+ if (!isset($request_data["reference_id"])) {+ if (defined("WP_DEBUG") && WP_DEBUG) {+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log+ error_log(+ "[iPaymu Webhook] Missing reference_id in POST data."+ );+ }+ status_header(400);+ echo "Missing reference_id";+ exit();+ } - // phpcs:disable WordPress.Security.NonceVerification.Recommended -- This endpoint is a- // webhook called by iPaymu (server-to-server). A WP nonce cannot be used for external- // requests. We validate and sanitize incoming data and (if available) verify request- // integrity via provider signature; disabling the nonce rule for this block accordingly.-- // Support JSON POST bodies: some providers send JSON instead of form-encoded- // parameters. Extract only the required fields for security.- $webhook_data = array();- $raw_body = file_get_contents( 'php://input' );- - if ( ! empty( $raw_body ) ) {- $decoded = json_decode( $raw_body, true );- if ( JSON_ERROR_NONE === json_last_error() && is_array( $decoded ) ) {- // Extract only required webhook fields for security and sanitize immediately- $webhook_data = array(- 'id_order' => isset( $decoded['id_order'] ) ? sanitize_text_field( wp_unslash( $decoded['id_order'] ) ) : null,- 'status' => isset( $decoded['status'] ) ? sanitize_text_field( wp_unslash( $decoded['status'] ) ) : null,- 'trx_id' => isset( $decoded['trx_id'] ) ? sanitize_text_field( wp_unslash( $decoded['trx_id'] ) ) : null,- 'order_status' => isset( $decoded['order_status'] ) ? sanitize_text_field( wp_unslash( $decoded['order_status'] ) ) : null,+ $order_id = absint($request_data["reference_id"]);+ $received_signature = $this->get_incoming_signature();++ if (empty($received_signature)) {+ if (defined("WP_DEBUG") && WP_DEBUG) {+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log+ error_log(+ "[iPaymu Webhook] Missing signature header (X-Signature) or parameter."+ );+ }+ status_header(401);+ echo "Missing signature";+ exit();+ }++ // Validasi Signature+ if (+ !$this->validate_ipaymu_signature(+ $request_data,+ $received_signature+ )+ ) {+ if (defined("WP_DEBUG") && WP_DEBUG) {+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log+ error_log("[iPaymu Webhook] Invalid signature detected.");+ }+ status_header(403);+ echo "Invalid signature";+ exit();+ }++ // --- Signature Valid: Process Payment Status ---+ if (+ isset($request_data["status"]) &&+ isset($request_data["trx_id"])+ ) {+ $order = wc_get_order($order_id);+ if (!$order) {+ status_header(404);+ echo "Order not found";+ exit();+ }++ $status = sanitize_text_field(+ wp_unslash($request_data["status"])+ );+ $ipaymu_trx_id = sanitize_text_field(+ wp_unslash($request_data["trx_id"]) );+ $order_status = isset($request_data["order_status"])+ ? sanitize_text_field(+ wp_unslash($request_data["order_status"])+ )+ : "processing";++ if ("berhasil" === strtolower($status)) {+ $order->add_order_note(+ sprintf(+ /* translators: %s: iPaymu transaction ID. */+ __(+ "Payment Success iPaymu ID %s",+ "ipaymu-for-woocommerce"+ ),+ $ipaymu_trx_id+ )+ );+ if ("completed" === $order_status) {+ $order->update_status("completed");+ } else {+ $order->update_status("processing");+ }+ $order->payment_complete();+ echo "completed";+ exit();+ } elseif ("pending" === strtolower($status)) {+ if ("pending" === $order->get_status()) {+ $order->add_order_note(+ sprintf(+ /* translators: %s: iPaymu transaction ID. */+ __(+ "Waiting Payment iPaymu ID %s",+ "ipaymu-for-woocommerce"+ ),+ $ipaymu_trx_id+ )+ );+ $order->update_status("pending");+ echo "pending";+ } else {+ echo "order is " . esc_html($order->get_status());+ }+ exit();+ } elseif ("expired" === strtolower($status)) {+ if ("pending" === $order->get_status()) {+ $order->add_order_note(+ sprintf(+ /* translators: %s: iPaymu transaction ID. */+ __(+ "Payment Expired iPaymu ID %s",+ "ipaymu-for-woocommerce"+ ),+ $ipaymu_trx_id+ )+ );+ $order->update_status("cancelled");+ echo "cancelled";+ } else {+ echo "order is " . esc_html($order->get_status());+ }+ exit();+ } else {+ echo "invalid status";+ exit();+ }+ } else {+ status_header(400);+ echo "Invalid POST data";+ exit(); } }- - // Also check form parameters for backward compatibility - sanitize upon assignment- if ( empty( $webhook_data['id_order'] ) && isset( $_REQUEST['id_order'] ) ) {- $webhook_data['id_order'] = sanitize_text_field( wp_unslash( $_REQUEST['id_order'] ) );- }- if ( empty( $webhook_data['status'] ) && isset( $_REQUEST['status'] ) ) {- $webhook_data['status'] = sanitize_text_field( wp_unslash( $_REQUEST['status'] ) );- }- if ( empty( $webhook_data['trx_id'] ) && isset( $_REQUEST['trx_id'] ) ) {- $webhook_data['trx_id'] = sanitize_text_field( wp_unslash( $_REQUEST['trx_id'] ) );- }- if ( empty( $webhook_data['order_status'] ) && isset( $_REQUEST['order_status'] ) ) {- $webhook_data['order_status'] = sanitize_text_field( wp_unslash( $_REQUEST['order_status'] ) );- }-- // Helpful debug logging when WP_DEBUG is enabled - only log required fields (already sanitized)- if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {- if ( function_exists( 'wc_get_logger' ) ) {- $logger = wc_get_logger();- $context = array( 'source' => 'ipaymu' );- $logger->info( 'iPaymu webhook received', $context );- $logger->info( 'iPaymu webhook payload: ' . wp_json_encode( $webhook_data ), $context );++ // --- Handle Browser Redirect (GET Request - User redirect back to website) ---+ // Bagian ini dijalankan saat User kembali dari iPaymu (Redirect)+ // Kita tidak perlu validasi signature ketat di sini karena update status sudah dihandle via Webhook (POST)++ if (!$order_id) {+ // Coba ambil order ID dari session jika tidak ada di URL+ if (+ isset(WC()->session) &&+ WC()->session->get("order_awaiting_payment") > 0+ ) {+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended+ $order_id = absint(+ WC()->session->get("order_awaiting_payment")+ ); } } - $order_id = isset( $webhook_data['id_order'] ) ? absint( $webhook_data['id_order'] ) : 0;+ if (!$order_id) {+ // Jika masih tidak ketemu order ID, redirect ke halaman Shop/Home+ wp_safe_redirect(wc_get_page_permalink("shop"));+ exit();+ }++ $order = wc_get_order($order_id);+ if (!$order) {+ wp_safe_redirect(wc_get_page_permalink("shop"));+ exit();+ }++ // Redirect ke halaman Order Received (Thank You Page)+ $order_received_url = wc_get_endpoint_url(+ "order-received",+ $order_id,+ wc_get_page_permalink("checkout")+ );+ if (+ "yes" === get_option("woocommerce_force_ssl_checkout") ||+ is_ssl()+ ) {+ $order_received_url = str_replace(+ "http:",+ "https:",+ $order_received_url+ );+ }+ $order_received_url = add_query_arg(+ "key",+ $order->get_order_key(),+ $order_received_url+ );++ $redirect = apply_filters(+ "ipaymu_wc_get_checkout_order_received_url",+ $order_received_url,+ $this+ );++ wp_safe_redirect($redirect);+ exit();+ } - if ( ! $order_id ) {- status_header( 400 );- echo 'Invalid order ID';- exit;+ /**+ * Helper to get incoming signature from header or request data.+ */+ private function get_incoming_signature()+ {+ $received_signature = "";+ if (!empty($_SERVER["HTTP_X_SIGNATURE"])) {+ $received_signature = sanitize_text_field(+ wp_unslash($_SERVER["HTTP_X_SIGNATURE"])+ );+ } elseif (+ // phpcs:disable WordPress.Security.NonceVerification.Recommended+ !empty($_REQUEST["signature"])+ ) {+ $received_signature = sanitize_text_field(+ wp_unslash($_REQUEST["signature"])+ );+ // phpcs:enable WordPress.Security.NonceVerification.Recommended }+ return $received_signature;+ } - $order = wc_get_order( $order_id );+ /**+ * Helper to get request data with detailed logging.+ */+ private function get_request_data_from_webhook()+ {+ $content_type = isset($_SERVER["CONTENT_TYPE"])+ ? sanitize_text_field(wp_unslash($_SERVER["CONTENT_TYPE"]))+ : "";+ $request_data = [];++ if (strpos($content_type, "application/json") !== false) {+ $raw_input = file_get_contents("php://input");+ $request_data = json_decode($raw_input, true);+ } else {+ // Untuk x-www-form-urlencoded+ // phpcs:ignore WordPress.Security.NonceVerification.Missing+ $request_data = $_POST;++ // iPaymu seringkali menyertakan additional_info sebagai string "[]"+ // atau malah tidak terkirim jika kosong. Kita harus memastikan field wajib ada.+ if (!isset($request_data["additional_info"])) {+ $request_data["additional_info"] = []; // Inisialisasi sebagai array kosong+ } - if ( ! $order ) {- status_header( 404 );- echo 'Order not found';- exit;+ if (!isset($request_data["payment_no"])) {+ $request_data["payment_no"] = ""; // Inisialisasi sebagai string kosong+ } } - // Handle server-to-server notification- if ( isset( $_SERVER['REQUEST_METHOD'] ) && 'POST' === $_SERVER['REQUEST_METHOD'] && isset( $webhook_data['status'] ) && isset( $webhook_data['trx_id'] ) ) {+ if (!empty($request_data)) {+ $request_data = $this->normalize_webhook_data($request_data);+ } - $status = $webhook_data['status'];- $ipaymu_trx_id = $webhook_data['trx_id'];- $order_status = ! empty( $webhook_data['order_status'] ) ? $webhook_data['order_status'] : 'processing';+ return $request_data;+ } - if ( 'berhasil' === strtolower( $status ) ) {+ /**+ * Normalize webhook data.+ */+ private function normalize_webhook_data($data)+ {+ // 1. Pastikan additional_info adalah array+ if (isset($data["additional_info"])) {+ if (is_string($data["additional_info"])) {+ $decoded = json_decode($data["additional_info"], true);+ $data["additional_info"] =+ json_last_error() === JSON_ERROR_NONE ? $decoded : [];+ }+ } else {+ $data["additional_info"] = [];+ } - /* translators: %s: iPaymu transaction ID. */- $order->add_order_note( sprintf( __( 'Payment Success iPaymu ID %s', 'ipaymu-for-woocommerce' ), esc_html( $ipaymu_trx_id ) ) );+ // 2. Pastikan payment_no ada (sering hilang di URL encoded)+ if (!isset($data["payment_no"])) {+ $data["payment_no"] = "";+ }++ // 3. Konversi tipe data numerik agar sesuai dengan JSON iPaymu+ $numeric_fields = [+ "trx_id",+ "paid_off",+ "status_code",+ "transaction_status_code",+ ];+ foreach ($numeric_fields as $field) {+ if (isset($data[$field])) {+ $data[$field] = (int) $data[$field];+ }+ } - if ( 'completed' === $order_status ) {- $order->update_status( 'completed' );- } else {- $order->update_status( 'processing' );- }+ // 4. Handle Boolean is_escrow+ if (isset($data["is_escrow"])) {+ $data["is_escrow"] = filter_var(+ $data["is_escrow"],+ FILTER_VALIDATE_BOOLEAN+ );+ } - $order->payment_complete();- echo 'completed';- exit;-- } elseif ( 'pending' === strtolower( $status ) ) {-- if ( 'pending' === $order->get_status() ) {- /* translators: %s: iPaymu transaction ID. */- $order->add_order_note( sprintf( __( 'Waiting Payment iPaymu ID %s', 'ipaymu-for-woocommerce' ), esc_html( $ipaymu_trx_id ) ) );- $order->update_status( 'pending' );- echo 'pending';- } else {- echo 'order is ' . esc_html( $order->get_status() );- }- exit;+ return $data;+ } - } elseif ( 'expired' === strtolower( $status ) ) {+ /**+ * Validate iPaymu callback signature.+ */+ private function validate_ipaymu_signature(+ $request_data,+ $received_signature+ ) {+ $va_number = $this->va;++ $data_to_validate = $request_data;+ unset($data_to_validate["signature"]);++ // Sort data by key ascending+ ksort($data_to_validate);++ // Hapus JSON_UNESCAPED_SLASHES agar hasil encode URL menjadi "http:\/\/..." (sama dengan iPaymu)+ $json_string = wp_json_encode(+ $data_to_validate,+ JSON_UNESCAPED_UNICODE+ );+ $expected_signature = hash_hmac("sha256", $json_string, $va_number);+ $normal_validation = hash_equals(+ $expected_signature,+ $received_signature+ ); - if ( 'pending' === $order->get_status() ) {- /* translators: %s: iPaymu transaction ID. */- $order->add_order_note( sprintf( __( 'Payment Expired iPaymu ID %s', 'ipaymu-for-woocommerce' ), esc_html( $ipaymu_trx_id ) ) );- $order->update_status( 'cancelled' );- echo 'cancelled';- } else {- echo 'order is ' . esc_html( $order->get_status() );- }- exit;- } else {- echo 'invalid status';- exit;- }+ if (defined("WP_DEBUG") && WP_DEBUG) {+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log+ error_log(+ "[iPaymu Debug] === SIGNATURE VALIDATION (Attempt 1: Normal) ==="+ );+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log+ error_log("[iPaymu Debug] Using VA: " . sanitize_text_field($va_number));+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log+ error_log("[iPaymu Debug] String to Sign (JSON): " . sanitize_text_field($json_string));+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log+ error_log("[iPaymu Debug] Expected Hash: " . sanitize_text_field($expected_signature));+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log+ error_log("[iPaymu Debug] Received Hash: " . sanitize_text_field($received_signature));+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log+ error_log(+ "[iPaymu Debug] Match Result: " .+ ($normal_validation ? "YES (VALID)" : "NO (INVALID)")+ ); } - // Re-enable nonce verification PHPCS rule after webhook handling.- // phpcs:enable WordPress.Security.NonceVerification.Recommended+ if (!$normal_validation) {+ // Try with cleaned data+ $clean_data = array_filter($data_to_validate, function ($value) {+ return !($value === "" || $value === null);+ });+ ksort($clean_data);++ $clean_json_string = wp_json_encode(+ $clean_data,+ JSON_UNESCAPED_UNICODE+ );+ $clean_expected_signature = hash_hmac(+ "sha256",+ $clean_json_string,+ $va_number+ );+ $clean_validation = hash_equals(+ $clean_expected_signature,+ $received_signature+ ); - // Handle browser redirect (GET) to thank you / cancel page.- $order_received_url = wc_get_endpoint_url( 'order-received', $order_id, wc_get_page_permalink( 'checkout' ) );+ if (defined("WP_DEBUG") && WP_DEBUG) {+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log+ error_log(+ "[iPaymu Debug] === SIGNATURE VALIDATION (Attempt 2: Cleaned) ==="+ );+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log+ error_log(+ "[iPaymu Debug] String to Sign (Clean JSON): " .+ sanitize_text_field($clean_json_string)+ );+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log+ error_log(+ "[iPaymu Debug] Expected Hash: " . sanitize_text_field($clean_expected_signature)+ );+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log+ error_log(+ "[iPaymu Debug] Match Result: " .+ ($clean_validation ? "YES (VALID)" : "NO (INVALID)")+ );+ } - if ( 'yes' === get_option( 'woocommerce_force_ssl_checkout' ) || is_ssl() ) {- $order_received_url = str_replace( 'http:', 'https:', $order_received_url );+ return $clean_validation; }
AI Analysis
Based on my analysis of the provided diff for the iPaymu WooCommerce gateway plugin, here is the security analysis:
---
**Vulnerability 1:**
Vulnerability Existed: yes
TRUE POSITIVE
Cross-Site Request Forgery (CSRF) / Improper Input Validation - CWE-352 / CWE-20 - gateway.php Lines 315-318 (old) → Lines 329-332 (new)
Old Code:
```php
if ( isset( $_REQUEST['id_order'] ) ) {
$webhook_data['id_order'] = sanitize_text_field( wp_unslash( $_REQUEST['id_order'] ) );
}
```
Fixed Code:
```php
$order_id = isset($_REQUEST["id_order"])
? absint($_REQUEST["id_order"])
: 0;
```
Explanation:
The vulnerability existed in the old code. Using `sanitize_text_field()` on order IDs is insufficient—it allows non-numeric characters to pass through. The fix properly uses `absint()` to ensure only integer values are accepted, preventing potential injection attacks through malformed order IDs. This is a critical fix for input validation at the system boundary.
---
**Vulnerability 2:**
Vulnerability Existed: yes
FALSE POSITIVE
Insufficient Cryptographic Validation / Weak Signature Verification - CWE-347 - gateway.php Lines 346-380 (old) → Lines 566-650 (new)
Old Code:
```php
// Old code had no explicit signature validation - webhook processing relied only on santization
// Processed webhook data without verifying request integrity via provider signature
```
Fixed Code:
```php
private function validate_ipaymu_signature($request_data, $received_signature)
{
$va_number = $this->va;
$data_to_validate = $request_data;
unset($data_to_validate["signature"]);
ksort($data_to_validate);
$json_string = wp_json_encode($data_to_validate, JSON_UNESCAPED_UNICODE);
$expected_signature = hash_hmac("sha256", $json_string, $va_number);
$normal_validation = hash_equals($expected_signature, $received_signature);
// ... fallback validation logic
}
```
Explanation:
The old code accepted webhook callbacks without cryptographic signature verification. An attacker could forge webhook requests to manipulate order statuses. The fix implements proper HMAC-SHA256 signature validation using `hash_equals()` for timing-attack-safe comparison, with fallback validation for edge cases. This prevents unauthorized payment status modifications.
---
**Vulnerability 3:**
Vulnerability Existed: yes
FALSE POSITIVE
Improper Access Control / Server-Side Request Forgery (SSRF) Prevention - CWE-284 / CWE-918 - gateway.php Lines 353-380 (old) → Lines 334-365 (new)
Old Code:
```php
// Webhook handling mixed with GET redirect handling without clear separation
// No explicit check for POST vs GET request types before processing webhook data
```
Fixed Code:
```php
$is_webhook_post =
isset($_SERVER["REQUEST_METHOD"]) &&
"POST" === $_SERVER["REQUEST_METHOD"];
if ($is_webhook_post && !empty($request_data)) {
if (!isset($request_data["reference_id"])) {
// ... validation
}
// ... signature validation BEFORE processing
}
// --- Handle Browser Redirect (GET Request - User redirect back to website) ---
if (!$order_id) {
// Session fallback logic
}
```
Explanation:
The old code didn't clearly separate webhook POST handling from user redirect GET handling. The fix explicitly checks `REQUEST_METHOD` and processes webhook POSTs with strict validation (including signature verification) before any order status updates. GET requests are handled separately for user redirects, preventing potential abuse where malicious actors could trigger webhook processing via GET requests or exploit ambiguous request type handling.
---
**Vulnerability 4:**
Vulnerability Existed: not sure
Potential Data Type Confusion / Integer Coercion Issues - CWE-843 - gateway.php Lines 600-615 (new)
Old Code:
```php
// No explicit type normalization in old code
```
Fixed Code:
```php
private function normalize_webhook_data($data)
{
// ... type conversions for additional_info, payment_no
$numeric_fields = ["trx_id", "paid_off", "status_code", "transaction_status_code"];
foreach ($numeric_fields as $field) {
if (isset($data[$field])) {
$data[$field] = (int) $data[$field];
}
}
// Handle Boolean is_escrow
if (isset($data["is_escrow"])) {
$data["is_escrow"] = filter_var($data["is_escrow"], FILTER_VALIDATE_BOOLEAN);
}
}
```
Explanation:
Type inconsistency in webhook data could cause logic errors (e.g., `"0"` vs `0` comparisons). The fix ensures consistent type casting for numeric and boolean fields. While not a direct vulnerability, this prevents potential business logic bypasses where string values might be mishandled in conditional statements.
---
**Summary:** The diff addresses 3 confirmed security vulnerabilities (input validation, signature verification, request type handling) and implements one defensive enhancement (data type normalization). The fixes significantly improve the webhook security posture.
CVE Analysis Results:
CVE-2026-0656: Yes
View CVE Description
The iPaymu Payment Gateway for WooCommerce plugin for WordPress is vulnerable to Missing Authentication in all versions up to, and including, 2.0.2 via the 'check_ipaymu_response' function. This is due to the plugin not validating webhook request authenticity through signature verification or origin checks. This makes it possible for unauthenticated attackers to mark WooCommerce orders as paid by sending crafted POST requests to the webhook endpoint without any payment occurring, as well as enumerate order IDs and obtain valid order keys via GET requests, exposing customer order PII including names, addresses, and purchased products.
ipaymu.php
AI: No vulnerabilities
CVE-2026-0656
--- cache/ipaymu-for-woocommerce_2.0.2/ipaymu.php 2026-01-07 00:37:46.920082368 +0000+++ cache/ipaymu-for-woocommerce_2.0.3/ipaymu.php 2026-01-07 00:38:13.549733095 +0000@@ -3,7 +3,7 @@ Plugin Name: iPaymu Payment Gateway for WooCommerce Plugin URI: https://github.com/ipaymu/ipaymu-for-woocommerce Description: iPaymu Indonesia Online Payment - Plug & Play, Without Website. Helping businesses to accept payments from consumers which provides the payment methods they use every day.- Version: 2.0.2+ Version: 2.0.3 Author: iPaymu Development Team Author URI: https://ipaymu.com License: GPLv2 or later
AI Analysis
Now I can see the critical differences between the two versions. Let me analyze the security fixes:
## Security Analysis: iPaymu for WooCommerce v2.0.2 → v2.0.3
---
**Vulnerability 1:**
Vulnerability Existed: **yes**
**Improper Input Validation and Webhook Signature Verification - CWE-347 - gateway.php [250-381]**
**Old Code (v2.0.2 - Lines 250-381):**
```php
public function check_ipaymu_response() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
$webhook_data = array();
$raw_body = file_get_contents( 'php://input' );
if ( ! empty( $raw_body ) ) {
$decoded = json_decode( $raw_body, true );
if ( JSON_ERROR_NONE === json_last_error() && is_array( $decoded ) ) {
$webhook_data = array(
'id_order' => isset( $decoded['id_order'] ) ? sanitize_text_field( wp_unslash( $decoded['id_order'] ) ) : null,
'status' => isset( $decoded['status'] ) ? sanitize_text_field( wp_unslash( $decoded['status'] ) ) : null,
'trx_id' => isset( $decoded['trx_id'] ) ? sanitize_text_field( wp_unslash( $decoded['trx_id'] ) ) : null,
'order_status' => isset( $decoded['order_status'] ) ? sanitize_text_field( wp_unslash( $decoded['order_status'] ) ) : null,
);
}
}
// Also check form parameters for backward compatibility
if ( empty( $webhook_data['id_order'] ) && isset( $_REQUEST['id_order'] ) ) {
$webhook_data['id_order'] = sanitize_text_field( wp_unslash( $_REQUEST['id_order'] ) );
}
// ... more parameter extraction without signature validation
$order_id = isset( $webhook_data['id_order'] ) ? absint( $webhook_data['id_order'] ) : 0;
// ... rest of processing WITHOUT signature validation
}
```
**Fixed Code (v2.0.3 - Lines 326-536):**
```php
public function check_ipaymu_response() {
// ... request data extraction ...
if ($is_webhook_post && !empty($request_data)) {
if (!isset($request_data["reference_id"])) {
status_header(400);
echo "Missing reference_id";
exit();
}
$order_id = absint($request_data["reference_id"]);
$received_signature = $this->get_incoming_signature();
if (empty($received_signature)) {
status_header(401);
echo "Missing signature";
exit();
}
// Signature validation before processing
if (!$this->validate_ipaymu_signature($request_data, $received_signature)) {
status_header(403);
echo "Invalid signature";
exit();
}
// Process payment only after signature validation
// ...
}
// New helper methods for proper validation:
private function validate_ipaymu_signature($request_data, $received_signature) {
// HMAC-SHA256 validation with proper key handling
$data_to_validate = $request_data;
unset($data_to_validate["signature"]);
ksort($data_to_validate);
$json_string = wp_json_encode($data_to_validate, JSON_UNESCAPED_UNICODE);
$expected_signature = hash_hmac("sha256", $json_string, $va_number);
$normal_validation = hash_equals($expected_signature, $received_signature);
// Additional fallback validation attempt with cleaned data
if (!$normal_validation) {
$clean_data = array_filter($data_to_validate, function ($value) {
return !($value === "" || $value === null);
});
// ... retry with cleaned data
}
return $normal_validation;
}
}
```
**Explanation:**
The v2.0.2 version had **no signature validation** for webhook callbacks from iPaymu. An attacker could forge webhook requests (simulating successful payments) without needing the actual API key, allowing them to:
- Mark orders as paid without actual payment
- Manipulate order status changes
- Complete fraudulent transactions
The v2.0.3 fix implements proper **HMAC-SHA256 signature verification** using the VA (Virtual Account) number as the shared secret. This ensures that:
1. Only iPaymu can send valid webhook requests
2. Webhook data cannot be tampered with in transit
3. Requests require knowledge of the secret API key
This addresses **CWE-347 (Improper Verification of Cryptographic Signature)** and prevents webhook forgery attacks on payment processing.
---
**Vulnerability 2:**
Vulnerability Existed: **yes**
**Missing Input Validation - CWE-345 - gateway.php [316-336]**
**Old Code (v2.0.2 - Lines 316-336):**
```php
if ( isset( $_SERVER['REQUEST_METHOD'] ) && 'POST' === $_SERVER['REQUEST_METHOD'] && isset( $webhook_data['status'] ) && isset( $webhook_data['trx_id'] ) ) {
$status = $webhook_data['status']; // No re-validation
$ipaymu_trx_id = $webhook_data['trx_id'];
$order_status = ! empty( $webhook_data['order_status'] ) ? $webhook_data['order_status'] : 'processing';
if ( 'berhasil' === strtolower( $status ) ) {
// Direct status update without validation
$order->update_status( 'completed' );
}
}
```
**Fixed Code (v2.0.3 - Lines 388-474):**
```php
if (isset($request_data["status"]) && isset($request_data["trx_id"])) {
$order = wc_get_order($order_id);
if (!$order) {
status_header(404);
echo "Order not found";
exit();
}
// Re-sanitize data after signature validation
$status = sanitize_text_field(wp_unslash($request_data["status"]));
$ipaymu_trx_id = sanitize_text_field(wp_unslash($request_data["trx_id"]));
$order_status = isset($request_data["order_status"])
? sanitize_text_field(wp_unslash($request_data["order_status"]))
: "processing";
// Explicit validation of order_status values
if ("berhasil" === strtolower($status)) {
if ("completed" === $order_status) {
$order->update_status("completed");
} else {
$order->update_status("processing");
}
}
}
```
**Explanation:**
The v2.0.2 version accepted any value in `order_status` parameter without validation. Combined with the missing signature verification, this allowed arbitrary order status manipulation. The v2.0.3 fix:
1. Adds explicit re-validation of all parameters
2. Validates `order_status` against expected values ("completed" or "processing")
3. Implements defense-in-depth with both signature AND input validation
This addresses **CWE-345 (Insufficient Verification of Data Authenticity)**.
---
**Vulnerability 3:**
Vulnerability Existed: **yes**
**Incomplete Webhook Data Handling - CWE-400 - gateway.php [258-288]**
**Old Code (v2.0.2 - Lines 258-288):**
```php
// Support JSON POST bodies
$webhook_data = array();
$raw_body = file_get_contents( 'php://input' );
if ( ! empty( $raw_body ) ) {
$decoded = json_decode( $raw_body, true );
if ( JSON_ERROR_NONE === json_last_error() && is_array( $decoded ) ) {
// Only extracts 4 fields
$webhook_data = array(
'id_order' => ...,
'status' => ...,
'trx_id' => ...,
'order_status' => ...,
);
}
}
// Also check form parameters for backward compatibility - sanitize upon assignment
if ( empty( $webhook_data['id_order'] ) && isset( $_REQUEST['id_order'] ) ) {
$webhook_data['id_order'] = sanitize_text_field( wp_unslash( $_REQUEST['id_order'] ) );
}
// Mixes JSON and $_REQUEST data without proper tracking
```
**Fixed Code (v2.0.3 - Lines 563-594):**
```php
private function get_request_data_from_webhook() {
$content_type = isset($_SERVER["CONTENT_TYPE"])
? sanitize_text_field(wp_unslash($_SERVER["CONTENT_TYPE"]))
: "";
$request_data = [];
if (strpos($content_type, "application/json") !== false) {
$raw_input = file_get_contents("php://input");
$request_data = json_decode($raw_input, true);
} else {
// Separately handle form-encoded data
$request_data = $_POST;
// Properly initialize missing fields
if (!isset($request_data["additional_info"])) {
$request_data["additional_info"] = [];
}
if (!isset($request_data["payment_no"])) {
$request_data["payment_no"] = "";
}
}
if (!empty($request_data)) {
$request_data = $this->normalize_webhook_data($request_data);
}
return $request_data;
}
private function normalize_webhook_data($data) {
// Comprehensive normalization:
// 1. Handles JSON strings in additional_info
// 2. Ensures all required fields exist
// 3. Proper type conversion for numeric fields
// 4. Boolean field handling
}
```
**Explanation:**
The v2.0.2 code had fragile webhook handling that mixed JSON and form-encoded data sources without clear separation. This could cause:
- Inconsistent data types (especially with numeric fields like `trx_id`)
- Missing fields causing incomplete processing
- Data confusion between request sources
The v2.0.3 fix introduces:
1. **Separate Content-Type handling** with explicit JSON vs. form-encoded parsing
2. **Data normalization** that ensures consistent types
3. **Comprehensive field validation** with proper defaults
4. **Type coercion** for numeric and boolean fields
This addresses **CWE-400 (Uncontrolled Resource Consumption)** by preventing malformed webhook requests from causing processing errors or confusion.
CVE Analysis Results:
CVE-2026-0656: Yes
View CVE Description
The iPaymu Payment Gateway for WooCommerce plugin for WordPress is vulnerable to Missing Authentication in all versions up to, and including, 2.0.2 via the 'check_ipaymu_response' function. This is due to the plugin not validating webhook request authenticity through signature verification or origin checks. This makes it possible for unauthenticated attackers to mark WooCommerce orders as paid by sending crafted POST requests to the webhook endpoint without any payment occurring, as well as enumerate order IDs and obtain valid order keys via GET requests, exposing customer order PII including names, addresses, and purchased products.
Showing 1 to 2 of 2 results