Make WordPress Core

Changeset 62762


Ignore:
Timestamp:
07/16/2026 02:35:01 AM (4 weeks ago)
Author:
ramonopoly
Message:

REST API: Reject non-string custom CSS in the global styles controller

This commit guards validate_custom_css() against non-string input, returning a rest_custom_css_invalid_type WP_Error with a 400 status instead of a fatal.

Before, styles.css had no type constraint in the global styles request schema, so a REST consumer could PUT an array (or any non-string value). That value reached strlen() in validate_custom_css() and threw an uncaught TypeError on PHP 8+.

Developed in: https://github.com/WordPress/wordpress-develop/pull/12549(https://github.com/WordPress/wordpress-develop/pull/12549)

Props andrewserong, ramonopoly.

Fixes #65640.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php

    r61557 r62762  
    674674         *              either through a STYLE end tag or a prefix of one which might become a
    675675         *              full end tag when combined with the contents of other styles.
     676         * @since 7.1.0 Rejects non-string values with a WP_Error instead of a fatal error.
    676677         *
    677678         * @see WP_Customize_Custom_CSS_Setting::validate()
    678679         *
    679          * @param string $css CSS to validate.
     680         * @param mixed $css CSS to validate.
    680681         * @return true|WP_Error True if the input was validated, otherwise WP_Error.
    681682         */
    682683        protected function validate_custom_css( $css ) {
     684                if ( ! is_string( $css ) ) {
     685                        return new WP_Error(
     686                                'rest_custom_css_invalid_type',
     687                                __( 'CSS must be a string.' ),
     688                                array( 'status' => 400 )
     689                        );
     690                }
     691
    683692                $length = strlen( $css );
    684693                for (
  • trunk/tests/phpunit/tests/rest-api/rest-global-styles-controller.php

    r61486 r62762  
    669669
    670670        /**
     671         * @covers WP_REST_Global_Styles_Controller::update_item
     672         * @ticket 65640
     673         */
     674        public function test_update_item_non_string_styles_css() {
     675                wp_set_current_user( self::$admin_id );
     676                if ( is_multisite() ) {
     677                        grant_super_admin( self::$admin_id );
     678                }
     679                $request = new WP_REST_Request( 'PUT', '/wp/v2/global-styles/' . self::$global_styles_id );
     680                $request->set_body_params(
     681                        array(
     682                                'styles' => array( 'css' => array( 'body { color: red; }' ) ),
     683                        )
     684                );
     685                $response = rest_get_server()->dispatch( $request );
     686                $this->assertErrorResponse( 'rest_custom_css_invalid_type', $response, 400 );
     687        }
     688
     689        /**
    671690         * Tests the submission of a custom block style variation that was defined
    672691         * within a theme style variation and wouldn't be registered at the time
     
    947966                );
    948967        }
     968
     969        /**
     970         * @covers WP_REST_Global_Styles_Controller::validate_custom_css
     971         * @ticket 65640
     972         *
     973         * @dataProvider data_custom_css_non_string
     974         *
     975         * @param mixed $custom_css Non-string value to validate.
     976         */
     977        public function test_validate_custom_css_non_string( $custom_css ) {
     978                $controller = new WP_REST_Global_Styles_Controller();
     979                $validate   = Closure::bind(
     980                        function ( $css ) {
     981                                return $this->validate_custom_css( $css );
     982                        },
     983                        $controller,
     984                        $controller
     985                );
     986
     987                $result = $validate( $custom_css );
     988                $this->assertWPError( $result );
     989                $this->assertSame( 'rest_custom_css_invalid_type', $result->get_error_code() );
     990        }
     991
     992        /**
     993         * Data provider.
     994         *
     995         * @return array<string, mixed[]>
     996         */
     997        public static function data_custom_css_non_string(): array {
     998                return array(
     999                        'array'   => array( array( 'body { color: red; }' ) ),
     1000                        'integer' => array( 123 ),
     1001                        'boolean' => array( true ),
     1002                        'null'    => array( null ),
     1003                        'object'  => array( new stdClass() ),
     1004                );
     1005        }
    9491006}
Note: See TracChangeset for help on using the changeset viewer.