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
 	 */