Commit 3a2fbf7158d for woocommerce
commit 3a2fbf7158dbe235fe6fdb25da8642a8b4f2471c
Author: Taha Paksu <3295+tpaksu@users.noreply.github.com>
Date: Mon May 11 11:10:32 2026 +0300
Fix unauthenticated access to guest order fulfillments via V4 REST API (#64757)
diff --git a/plugins/woocommerce/src/Internal/RestApi/Routes/V4/Fulfillments/Controller.php b/plugins/woocommerce/src/Internal/RestApi/Routes/V4/Fulfillments/Controller.php
index 9941157a922..371cb168194 100644
--- a/plugins/woocommerce/src/Internal/RestApi/Routes/V4/Fulfillments/Controller.php
+++ b/plugins/woocommerce/src/Internal/RestApi/Routes/V4/Fulfillments/Controller.php
@@ -370,9 +370,10 @@ class Controller extends AbstractController {
}
// Check if the order exists, and if the current user is the owner of the order, and the request is a read request.
- // We allow this because we need to render the order fulfillments on the customer's order details and order tracking pages.
- // But they will be only able to view them, not edit.
- if ( get_current_user_id() === $order->get_customer_id() && WP_REST_Server::READABLE === $request->get_method() ) {
+ // Guest order fulfillments are rendered server-side via templates, so they don't need REST API access.
+ // The get_current_user_id() > 0 check prevents unauthenticated users from accessing guest orders
+ // where both get_current_user_id() and get_customer_id() would return 0.
+ if ( get_current_user_id() > 0 && get_current_user_id() === $order->get_customer_id() && WP_REST_Server::READABLE === $request->get_method() ) {
return true;
}
diff --git a/plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Fulfillments/ControllerTest.php b/plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Fulfillments/ControllerTest.php
index d6a8f46fdd3..fe984e82ddf 100644
--- a/plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Fulfillments/ControllerTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/RestApi/Routes/V4/Fulfillments/ControllerTest.php
@@ -404,6 +404,32 @@ class ControllerTest extends WC_REST_Unit_Test_Case {
$this->assertEquals( 401, $response->get_status() );
}
+ /**
+ * Regression test for WOO13-227: an unauthenticated request must not be
+ * able to read a guest order's fulfillments. The owner-read check compares
+ * get_current_user_id() to $order->get_customer_id(); for guest orders
+ * both are 0, so the check needs a `get_current_user_id() > 0` guard.
+ */
+ public function test_permission_check_unauthenticated_cannot_read_guest_order_fulfillments() {
+ $guest_order = WC_Helper_Order::create_order( 0 );
+ $guest_fulfillment = FulfillmentsHelper::create_fulfillment(
+ array( 'entity_id' => $guest_order->get_id() )
+ );
+
+ wp_set_current_user( 0 );
+
+ $list_request = new WP_REST_Request( 'GET', '/wc/v4/fulfillments' );
+ $list_request->set_param( 'order_id', $guest_order->get_id() );
+ $list_response = rest_get_server()->dispatch( $list_request );
+ $this->assertSame( 401, $list_response->get_status() );
+
+ $get_request = new WP_REST_Request( 'GET', '/wc/v4/fulfillments/' . $guest_fulfillment->get_id() );
+ $get_response = rest_get_server()->dispatch( $get_request );
+ $this->assertSame( 401, $get_response->get_status() );
+
+ WC_Helper_Order::delete_order( $guest_order->get_id() );
+ }
+
/**
* Test permission check - customer accessing other's order
*/