diff --git a/wp-includes/kses.php b/wp-includes/kses.php index 8cc521346a..964ef7fd6e 100644 --- a/wp-includes/kses.php +++ b/wp-includes/kses.php @@ -1985,9 +1985,7 @@ function safecss_filter_attr( $css, $deprecated = '' ) { $css = wp_kses_no_null( $css ); $css = str_replace( array( "\n", "\r", "\t" ), '', $css ); - if ( preg_match( '%[\\\\(&=}]|/\*%', $css ) ) { // remove any inline css containing \ ( & } = or comments - return ''; - } + $allowed_protocols = wp_allowed_protocols(); $css_array = explode( ';', trim( $css ) ); @@ -1998,6 +1996,7 @@ function safecss_filter_attr( $css, $deprecated = '' ) { * @since 4.4.0 Added support for `min-height`, `max-height`, `min-width`, and `max-width`. * @since 4.6.0 Added support for `list-style-type`. * @since 5.0.0 Added support for `text-transform`. + * @since 5.0.0 Added support for `background-image`. * * @param string[] $attr Array of allowed CSS attributes. */ @@ -2006,6 +2005,7 @@ function safecss_filter_attr( $css, $deprecated = '' ) { array( 'background', 'background-color', + 'background-image', 'border', 'border-width', @@ -2076,6 +2076,24 @@ function safecss_filter_attr( $css, $deprecated = '' ) { ) ); + /* + * CSS attributes that accept URL data types. + * + * This is in accordance to the CSS spec and unrelated to + * the sub-set of supported attributes above. + * + * See: https://developer.mozilla.org/en-US/docs/Web/CSS/url + */ + $css_url_data_types = array( + 'background', + 'background-image', + + 'cursor', + + 'list-style', + 'list-style-image', + ); + if ( empty( $allowed_attr ) ) { return $css; } @@ -2085,20 +2103,55 @@ function safecss_filter_attr( $css, $deprecated = '' ) { if ( $css_item == '' ) { continue; } - $css_item = trim( $css_item ); - $found = false; + + $css_item = trim( $css_item ); + $css_test_string = $css_item; + $found = false; + $url_attr = false; + if ( strpos( $css_item, ':' ) === false ) { $found = true; } else { - $parts = explode( ':', $css_item ); - if ( in_array( trim( $parts[0] ), $allowed_attr ) ) { - $found = true; + $parts = explode( ':', $css_item, 2 ); + $css_selector = trim( $parts[0] ); + + if ( in_array( $css_selector, $allowed_attr, true ) ) { + $found = true; + $url_attr = in_array( $css_selector, $css_url_data_types, true ); } } - if ( $found ) { + + if ( $found && $url_attr ) { + // Simplified: matches the sequence `url(*)`. + preg_match_all( '/url\([^)]+\)/', $parts[1], $url_matches ); + + foreach ( $url_matches[0] as $url_match ) { + // Clean up the URL from each of the matches above. + preg_match( '/^url\(\s*([\'\"]?)(.*)(\g1)\s*\)$/', $url_match, $url_pieces ); + + if ( empty( $url_pieces[2] ) ) { + $found = false; + break; + } + + $url = trim( $url_pieces[2] ); + + if ( empty( $url ) || $url !== wp_kses_bad_protocol( $url, $allowed_protocols ) ) { + $found = false; + break; + } else { + // Remove the whole `url(*)` bit that was matched above from the CSS. + $css_test_string = str_replace( $url_match, '', $css_test_string ); + } + } + } + + // Remove any CSS containing containing \ ( & } = or comments, except for url() useage checked above. + if ( $found && ! preg_match( '%[\\\(&=}]|/\*%', $css_test_string ) ) { if ( $css != '' ) { $css .= ';'; } + $css .= $css_item; } } diff --git a/wp-includes/version.php b/wp-includes/version.php index 831a2b52bd..2889bc6514 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -13,7 +13,7 @@ * * @global string $wp_version */ -$wp_version = '5.1-alpha-44135'; +$wp_version = '5.1-alpha-44136'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.