Commit a24559f5941 for woocommerce

commit a24559f59411fee0c41f1ad08c9eafa93e19df51
Author: Thomas Roberts <5656702+opr@users.noreply.github.com>
Date:   Fri Mar 13 12:09:27 2026 +0000

    Fix stored XSS on order notes in REST API v4 (#63661)

    * Fix stored XSS on order notes in REST API v4

    Add wp_kses_post sanitize_callback to the note field in the v4
    OrderNoteSchema, matching the fix applied to v1/v2/v3 in #63616.

    Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

    * Add changelog entry for v4 order notes XSS fix

    Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

    * Fix stored XSS on order notes in REST API v4

    Sanitize note content with wp_kses_post() in the v4 OrderNotes
    controller's create_item method, matching the fix applied to
    v1/v2/v3 in #63616.

    Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

    ---------

    Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

diff --git a/plugins/woocommerce/changelog/fix-xss-order-notes-v4 b/plugins/woocommerce/changelog/fix-xss-order-notes-v4
new file mode 100644
index 00000000000..3251735454b
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-xss-order-notes-v4
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Prevent stored XSS on order notes added via REST API v4
diff --git a/plugins/woocommerce/src/Internal/RestApi/Routes/V4/OrderNotes/Controller.php b/plugins/woocommerce/src/Internal/RestApi/Routes/V4/OrderNotes/Controller.php
index 8538225e5bd..af3f8c9c586 100644
--- a/plugins/woocommerce/src/Internal/RestApi/Routes/V4/OrderNotes/Controller.php
+++ b/plugins/woocommerce/src/Internal/RestApi/Routes/V4/OrderNotes/Controller.php
@@ -287,7 +287,7 @@ class Controller extends AbstractController {
 		}

 		$order   = $this->get_order_by_id( (int) $request['order_id'] );
-		$note_id = $order ? $order->add_order_note( $request['note'], $request['is_customer_note'], true ) : null;
+		$note_id = $order ? $order->add_order_note( wp_kses_post( $request['note'] ), $request['is_customer_note'], true ) : null;

 		if ( ! $note_id ) {
 			return $this->get_route_error_by_code( self::CANNOT_CREATE );
diff --git a/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version4/OrderNotes/class-wc-rest-order-notes-v4-controller-tests.php b/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version4/OrderNotes/class-wc-rest-order-notes-v4-controller-tests.php
index 3e15847e812..a06f730ebf3 100644
--- a/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version4/OrderNotes/class-wc-rest-order-notes-v4-controller-tests.php
+++ b/plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version4/OrderNotes/class-wc-rest-order-notes-v4-controller-tests.php
@@ -387,6 +387,29 @@ class WC_REST_Order_Notes_V4_Controller_Tests extends WC_REST_Unit_Test_Case {
 		$this->assertEquals( 401, $response->get_status() );
 	}

+	/**
+	 * Test that order note content is sanitized to prevent XSS.
+	 */
+	public function test_create_item_sanitizes_note_content() {
+		$order = OrderHelper::create_order( $this->user );
+
+		$request = new WP_REST_Request( 'POST', '/wc/v4/order-notes' );
+		$request->set_body_params(
+			array(
+				'order_id' => $order->get_id(),
+				'note'     => '<script>alert("xss")</script>Safe content<b>bold</b>',
+			)
+		);
+
+		$response = $this->server->dispatch( $request );
+		$data     = $response->get_data();
+
+		$this->assertEquals( 201, $response->get_status() );
+		$this->assertStringNotContainsString( '<script>', $data['note'] );
+		$this->assertStringContainsString( 'Safe content', $data['note'] );
+		$this->assertStringContainsString( '<b>bold</b>', $data['note'] );
+	}
+
 	/**
 	 * Test deleting order note without permission.
 	 */