Commit 5114d45d09 for wordpress.org

commit 5114d45d09e8ba1885aac58a4fa712faf83b627e
Author: gziolo <gziolo@git.wordpress.org>
Date:   Tue Nov 10 04:16:59 2026 +0000

    Abilities API: Skip redundant input sanitization in the REST run endpoint

    The permission callback and `WP_Ability::execute()` already normalize, validate, and coerce input. The `input` argument now sets `sanitize_callback` to `null`, so both receive the original raw input. `sanitize_input_for_ability()` is deprecated and returns its input unchanged.

    Follow-up to [62674], [65044].

    Developed in https://github.com/WordPress/wordpress-develop/pull/15684.

    Props gziolo, jorgefilipecosta, euvoor, justlevine.
    Fixes #66383.



    Built from https://develop.svn.wordpress.org/trunk@65368


    git-svn-id: http://core.svn.wordpress.org/trunk@64507 1a063a9b-81f0-0310-95a4-ce76da25c4cd

diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php
index f92eafe3f6..631bc59bf1 100644
--- a/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php
+++ b/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php
@@ -149,6 +149,7 @@ class WP_REST_Abilities_V1_Run_Controller extends WP_REST_Controller {
 	 * Checks if a given request has permission to execute a specific ability.
 	 *
 	 * @since 6.9.0
+	 * @since 7.2.0 Prepares the input read from the raw request.
 	 *
 	 * @param WP_REST_Request $request Full details about the request.
 	 * @return true|WP_Error True if the request has execution permission, WP_Error object otherwise.
@@ -171,18 +172,7 @@ class WP_REST_Abilities_V1_Run_Controller extends WP_REST_Controller {
 			return $is_valid;
 		}

-		$input = $this->get_input_from_request( $request );
-		$input = $ability->normalize_input( $input );
-		if ( is_wp_error( $input ) ) {
-			return $this->ensure_error_status( $input, 400 );
-		}
-
-		$is_valid = $ability->validate_input( $input );
-		if ( is_wp_error( $is_valid ) ) {
-			return $this->ensure_error_status( $is_valid, 400 );
-		}
-
-		$input = $ability->coerce_input( $input );
+		$input = $this->prepare_input_for_ability( $ability, $this->get_input_from_request( $request ) );
 		if ( is_wp_error( $input ) ) {
 			return $this->ensure_error_status( $input, 400 );
 		}
@@ -242,30 +232,42 @@ class WP_REST_Abilities_V1_Run_Controller extends WP_REST_Controller {
 	}

 	/**
-	 * Sanitizes the run input by coercing it to the ability's input schema.
+	 * Returns run input unchanged for backward compatibility.
 	 *
-	 * Registered as the `input` argument `sanitize_callback` so request input is coerced
-	 * before any route callback runs, regardless of transport. `check_ability_permissions()`
-	 * and `WP_Ability::execute()` coerce the input again after normalization and validation,
-	 * so schema defaults and values from normalization filters are coerced too.
+	 * This method is no longer registered as the input argument sanitizer.
 	 *
 	 * @since 7.1.0
-	 *
-	 * @see WP_Ability::coerce_input()
+	 * @deprecated 7.2.0 Input is prepared by `check_ability_permissions()` and `WP_Ability::execute()`.
 	 *
 	 * @param mixed           $input   Raw input extracted from the request.
-	 * @param WP_REST_Request $request The request object.
-	 * @return mixed|WP_Error Coerced input, raw input when validation fails, or WP_Error when coercion fails.
+	 * @param WP_REST_Request $request Unused. The request object.
+	 * @return mixed The unchanged input.
 	 */
 	public function sanitize_input_for_ability( $input, $request ) {
-		$ability = wp_has_ability( $request['name'] ) ? wp_get_ability( $request['name'] ) : null;
-		if ( ! $ability instanceof WP_Ability ) {
+		_deprecated_function( __METHOD__, '7.2.0' );
+
+		return $input;
+	}
+
+	/**
+	 * Normalizes, validates, and coerces input for an ability.
+	 *
+	 * @since 7.2.0
+	 *
+	 * @param WP_Ability $ability The ability to prepare input for.
+	 * @param mixed      $input   Input to prepare.
+	 * @return mixed|WP_Error Prepared input, or `WP_Error` when normalization, validation, or coercion fails.
+	 */
+	private function prepare_input_for_ability( WP_Ability $ability, $input ) {
+		$input = $ability->normalize_input( $input );
+		if ( is_wp_error( $input ) ) {
 			return $input;
 		}

 		// Validate before coercion so sanitization cannot rescue invalid input.
-		if ( null === $input || empty( $ability->get_input_schema() ) || is_wp_error( $ability->validate_input( $input ) ) ) {
-			return $input;
+		$is_valid = $ability->validate_input( $input );
+		if ( is_wp_error( $is_valid ) ) {
+			return $is_valid;
 		}

 		return $ability->coerce_input( $input );
@@ -284,7 +286,8 @@ class WP_REST_Abilities_V1_Run_Controller extends WP_REST_Controller {
 				'description'       => __( 'Input parameters for the ability execution.' ),
 				'type'              => array( 'integer', 'number', 'boolean', 'string', 'array', 'object', 'null' ),
 				'default'           => null,
-				'sanitize_callback' => array( $this, 'sanitize_input_for_ability' ),
+				// Keep the raw input for the permission check and execution. This disables default REST coercion.
+				'sanitize_callback' => null,
 			),
 		);
 	}
diff --git a/wp-includes/version.php b/wp-includes/version.php
index 09c0812203..eb651d0c42 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
  *
  * @global string $wp_version
  */
-$wp_version = '7.2-beta4-65367';
+$wp_version = '7.2-beta4-65368';

 /**
  * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.