Make WordPress Core


Ignore:
Timestamp:
12/14/2018 01:40:50 AM (7 years ago)
Author:
pento
Message:

KSES: Allow url() to be used in inline CSS.

The cover image block uses the url() function in its inline CSS, to show the cover image. KSES didn't allow this, causing the block to not save correctly for Author and Contributor users. As KSES does already check each attribute name against an allowed list, we're able to add an extra check for certain attributes to be able to use the url() function, too.

Merges [43781] from the 5.0 branch to core.

Props peterwilsoncc, azaozz, pento, dd32.
Fixes #45067.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/wp-includes/kses.php

    r43984 r44136  
    19861986    $css = str_replace( array( "\n", "\r", "\t" ), '', $css );
    19871987
    1988     if ( preg_match( '%[\\\\(&=}]|/\*%', $css ) ) { // remove any inline css containing \ ( & } = or comments
    1989         return '';
    1990     }
     1988    $allowed_protocols = wp_allowed_protocols();
    19911989
    19921990    $css_array = explode( ';', trim( $css ) );
     
    19991997     * @since 4.6.0 Added support for `list-style-type`.
    20001998     * @since 5.0.0 Added support for `text-transform`.
     1999     * @since 5.0.0 Added support for `background-image`.
    20012000     *
    20022001     * @param string[] $attr Array of allowed CSS attributes.
     
    20072006            'background',
    20082007            'background-color',
     2008            'background-image',
    20092009
    20102010            'border',
     
    20772077    );
    20782078
     2079    /*
     2080     * CSS attributes that accept URL data types.
     2081     *
     2082     * This is in accordance to the CSS spec and unrelated to
     2083     * the sub-set of supported attributes above.
     2084     *
     2085     * See: https://developer.mozilla.org/en-US/docs/Web/CSS/url
     2086     */
     2087    $css_url_data_types = array(
     2088        'background',
     2089        'background-image',
     2090
     2091        'cursor',
     2092
     2093        'list-style',
     2094        'list-style-image',
     2095    );
     2096
    20792097    if ( empty( $allowed_attr ) ) {
    20802098        return $css;
     
    20862104            continue;
    20872105        }
    2088         $css_item = trim( $css_item );
    2089         $found    = false;
     2106
     2107        $css_item        = trim( $css_item );
     2108        $css_test_string = $css_item;
     2109        $found           = false;
     2110        $url_attr        = false;
     2111
    20902112        if ( strpos( $css_item, ':' ) === false ) {
    20912113            $found = true;
    20922114        } else {
    2093             $parts = explode( ':', $css_item );
    2094             if ( in_array( trim( $parts[0] ), $allowed_attr ) ) {
    2095                 $found = true;
     2115            $parts        = explode( ':', $css_item, 2 );
     2116            $css_selector = trim( $parts[0] );
     2117
     2118            if ( in_array( $css_selector, $allowed_attr, true ) ) {
     2119                $found    = true;
     2120                $url_attr = in_array( $css_selector, $css_url_data_types, true );
    20962121            }
    20972122        }
    2098         if ( $found ) {
     2123
     2124        if ( $found && $url_attr ) {
     2125            // Simplified: matches the sequence `url(*)`.
     2126            preg_match_all( '/url\([^)]+\)/', $parts[1], $url_matches );
     2127
     2128            foreach ( $url_matches[0] as $url_match ) {
     2129                // Clean up the URL from each of the matches above.
     2130                preg_match( '/^url\(\s*([\'\"]?)(.*)(\g1)\s*\)$/', $url_match, $url_pieces );
     2131
     2132                if ( empty( $url_pieces[2] ) ) {
     2133                    $found = false;
     2134                    break;
     2135                }
     2136
     2137                $url = trim( $url_pieces[2] );
     2138
     2139                if ( empty( $url ) || $url !== wp_kses_bad_protocol( $url, $allowed_protocols ) ) {
     2140                    $found = false;
     2141                    break;
     2142                } else {
     2143                    // Remove the whole `url(*)` bit that was matched above from the CSS.
     2144                    $css_test_string = str_replace( $url_match, '', $css_test_string );
     2145                }
     2146            }
     2147        }
     2148
     2149        // Remove any CSS containing containing \ ( & } = or comments, except for url() useage checked above.
     2150        if ( $found && ! preg_match( '%[\\\(&=}]|/\*%', $css_test_string ) ) {
    20992151            if ( $css != '' ) {
    21002152                $css .= ';';
    21012153            }
     2154
    21022155            $css .= $css_item;
    21032156        }
Note: See TracChangeset for help on using the changeset viewer.