--- a/wp/wp-includes/kses.php Wed Sep 21 18:19:35 2022 +0200
+++ b/wp/wp-includes/kses.php Tue Sep 27 16:37:53 2022 +0200
@@ -81,16 +81,10 @@
'target' => true,
),
'article' => array(
- 'align' => true,
- 'dir' => true,
- 'lang' => true,
- 'xml:lang' => true,
+ 'align' => true,
),
'aside' => array(
- 'align' => true,
- 'dir' => true,
- 'lang' => true,
- 'xml:lang' => true,
+ 'align' => true,
),
'audio' => array(
'autoplay' => true,
@@ -101,14 +95,10 @@
'src' => true,
),
'b' => array(),
- 'bdo' => array(
- 'dir' => true,
- ),
+ 'bdo' => array(),
'big' => array(),
'blockquote' => array(
- 'cite' => true,
- 'lang' => true,
- 'xml:lang' => true,
+ 'cite' => true,
),
'br' => array(),
'button' => array(
@@ -120,17 +110,13 @@
'caption' => array(
'align' => true,
),
- 'cite' => array(
- 'dir' => true,
- 'lang' => true,
- ),
+ 'cite' => array(),
'code' => array(),
'col' => array(
'align' => true,
'char' => true,
'charoff' => true,
'span' => true,
- 'dir' => true,
'valign' => true,
'width' => true,
),
@@ -148,33 +134,21 @@
'dd' => array(),
'dfn' => array(),
'details' => array(
- 'align' => true,
- 'dir' => true,
- 'lang' => true,
- 'open' => true,
- 'xml:lang' => true,
+ 'align' => true,
+ 'open' => true,
),
'div' => array(
- 'align' => true,
- 'dir' => true,
- 'lang' => true,
- 'xml:lang' => true,
+ 'align' => true,
),
'dl' => array(),
'dt' => array(),
'em' => array(),
'fieldset' => array(),
'figure' => array(
- 'align' => true,
- 'dir' => true,
- 'lang' => true,
- 'xml:lang' => true,
+ 'align' => true,
),
'figcaption' => array(
- 'align' => true,
- 'dir' => true,
- 'lang' => true,
- 'xml:lang' => true,
+ 'align' => true,
),
'font' => array(
'color' => true,
@@ -182,10 +156,7 @@
'size' => true,
),
'footer' => array(
- 'align' => true,
- 'dir' => true,
- 'lang' => true,
- 'xml:lang' => true,
+ 'align' => true,
),
'h1' => array(
'align' => true,
@@ -206,16 +177,10 @@
'align' => true,
),
'header' => array(
- 'align' => true,
- 'dir' => true,
- 'lang' => true,
- 'xml:lang' => true,
+ 'align' => true,
),
'hgroup' => array(
- 'align' => true,
- 'dir' => true,
- 'lang' => true,
- 'xml:lang' => true,
+ 'align' => true,
),
'hr' => array(
'align' => true,
@@ -253,10 +218,7 @@
'value' => true,
),
'main' => array(
- 'align' => true,
- 'dir' => true,
- 'lang' => true,
- 'xml:lang' => true,
+ 'align' => true,
),
'map' => array(
'name' => true,
@@ -266,16 +228,20 @@
'type' => true,
),
'nav' => array(
- 'align' => true,
- 'dir' => true,
- 'lang' => true,
- 'xml:lang' => true,
+ 'align' => true,
+ ),
+ 'object' => array(
+ 'data' => array(
+ 'required' => true,
+ 'value_callback' => '_wp_kses_allow_pdf_objects',
+ ),
+ 'type' => array(
+ 'required' => true,
+ 'values' => array( 'application/pdf' ),
+ ),
),
'p' => array(
- 'align' => true,
- 'dir' => true,
- 'lang' => true,
- 'xml:lang' => true,
+ 'align' => true,
),
'pre' => array(
'width' => true,
@@ -283,29 +249,25 @@
'q' => array(
'cite' => true,
),
+ 'rb' => array(),
+ 'rp' => array(),
+ 'rt' => array(),
+ 'rtc' => array(),
+ 'ruby' => array(),
's' => array(),
'samp' => array(),
'span' => array(
- 'dir' => true,
- 'align' => true,
- 'lang' => true,
- 'xml:lang' => true,
+ 'align' => true,
),
'section' => array(
- 'align' => true,
- 'dir' => true,
- 'lang' => true,
- 'xml:lang' => true,
+ 'align' => true,
),
'small' => array(),
'strike' => array(),
'strong' => array(),
'sub' => array(),
'summary' => array(
- 'align' => true,
- 'dir' => true,
- 'lang' => true,
- 'xml:lang' => true,
+ 'align' => true,
),
'sup' => array(),
'table' => array(
@@ -314,7 +276,6 @@
'border' => true,
'cellpadding' => true,
'cellspacing' => true,
- 'dir' => true,
'rules' => true,
'summary' => true,
'width' => true,
@@ -333,7 +294,6 @@
'char' => true,
'charoff' => true,
'colspan' => true,
- 'dir' => true,
'headers' => true,
'height' => true,
'nowrap' => true,
@@ -452,7 +412,7 @@
);
/**
- * @var string[] $allowedentitynames Array of KSES allowed HTML entitity names.
+ * @var string[] $allowedentitynames Array of KSES allowed HTML entity names.
* @since 1.0.0
*/
$allowedentitynames = array(
@@ -712,10 +672,10 @@
);
/**
- * @var string[] $allowedxmlentitynames Array of KSES allowed XML entitity names.
+ * @var string[] $allowedxmlentitynames Array of KSES allowed XML entity names.
* @since 5.5.0
*/
- $allowedxmlnamedentities = array(
+ $allowedxmlentitynames = array(
'amp',
'lt',
'gt',
@@ -846,22 +806,30 @@
*
* @param string|array $context The context for which to retrieve tags. Allowed values are 'post',
* 'strip', 'data', 'entities', or the name of a field filter such as
- * 'pre_user_description'.
+ * 'pre_user_description', or an array of allowed HTML elements and attributes.
* @return array Array of allowed HTML tags and their allowed attributes.
*/
function wp_kses_allowed_html( $context = '' ) {
global $allowedposttags, $allowedtags, $allowedentitynames;
if ( is_array( $context ) ) {
+ // When `$context` is an array it's actually an array of allowed HTML elements and attributes.
+ $html = $context;
+ $context = 'explicit';
+
/**
- * Filters the HTML that is allowed for a given context.
+ * Filters the HTML tags that are allowed for a given context.
+ *
+ * HTML tags and attribute names are case-insensitive in HTML but must be
+ * added to the KSES allow list in lowercase. An item added to the allow list
+ * in upper or mixed case will not recognized as permitted by KSES.
*
* @since 3.5.0
*
- * @param array[]|string $context Context to judge allowed tags by.
- * @param string $context_type Context name.
+ * @param array[] $html Allowed HTML tags.
+ * @param string $context Context name.
*/
- return apply_filters( 'wp_kses_allowed_html', $context, 'explicit' );
+ return apply_filters( 'wp_kses_allowed_html', $html, $context );
}
switch ( $context ) {
@@ -1040,7 +1008,7 @@
* or a context name such as 'post'.
* @global string[] $pass_allowed_protocols Array of allowed URL protocols.
*
- * @param array $matches preg_replace regexp matches
+ * @param array $match preg_replace regexp matches
* @return string
*/
function _wp_kses_split_callback( $match ) {
@@ -1126,12 +1094,22 @@
* Removes all attributes, if none are allowed for this element.
*
* If some are allowed it calls `wp_kses_hair()` to split them further, and then
- * it builds up new HTML code from the data that `kses_hair()` returns. It also
+ * it builds up new HTML code from the data that `wp_kses_hair()` returns. It also
* removes `<` and `>` characters, if there are any left. One more thing it does
* is to check if the tag has a closing XHTML slash, and if it does, it puts one
* in the returned code as well.
*
+ * An array of allowed values can be defined for attributes. If the attribute value
+ * doesn't fall into the list, the attribute will be removed from the tag.
+ *
+ * Attributes can be marked as required. If a required attribute is not present,
+ * KSES will remove all attributes from the tag. As KSES doesn't match opening and
+ * closing tags, it's not possible to safely remove the tag itself, the safest
+ * fallback is to strip all attributes from the tag, instead.
+ *
* @since 1.0.0
+ * @since 5.9.0 Added support for an array of allowed values for attributes.
+ * Added support for required attributes.
*
* @param string $element HTML element/tag.
* @param string $attr HTML attributes from HTML element to closing HTML element tag.
@@ -1161,15 +1139,48 @@
// Split it.
$attrarr = wp_kses_hair( $attr, $allowed_protocols );
- // Go through $attrarr, and save the allowed attributes for this element
- // in $attr2.
+ // Check if there are attributes that are required.
+ $required_attrs = array_filter(
+ $allowed_html[ $element_low ],
+ function( $required_attr_limits ) {
+ return isset( $required_attr_limits['required'] ) && true === $required_attr_limits['required'];
+ }
+ );
+
+ /*
+ * If a required attribute check fails, we can return nothing for a self-closing tag,
+ * but for a non-self-closing tag the best option is to return the element with attributes,
+ * as KSES doesn't handle matching the relevant closing tag.
+ */
+ $stripped_tag = '';
+ if ( empty( $xhtml_slash ) ) {
+ $stripped_tag = "<$element>";
+ }
+
+ // Go through $attrarr, and save the allowed attributes for this element in $attr2.
$attr2 = '';
foreach ( $attrarr as $arreach ) {
+ // Check if this attribute is required.
+ $required = isset( $required_attrs[ strtolower( $arreach['name'] ) ] );
+
if ( wp_kses_attr_check( $arreach['name'], $arreach['value'], $arreach['whole'], $arreach['vless'], $element, $allowed_html ) ) {
$attr2 .= ' ' . $arreach['whole'];
+
+ // If this was a required attribute, we can mark it as found.
+ if ( $required ) {
+ unset( $required_attrs[ strtolower( $arreach['name'] ) ] );
+ }
+ } elseif ( $required ) {
+ // This attribute was required, but didn't pass the check. The entire tag is not allowed.
+ return $stripped_tag;
}
}
+ // If some required attributes weren't set, the entire tag is not allowed.
+ if ( ! empty( $required_attrs ) ) {
+ return $stripped_tag;
+ }
+
// Remove any "<" or ">" characters.
$attr2 = preg_replace( '/[<>]/', '', $attr2 );
@@ -1180,7 +1191,7 @@
* Determines whether an attribute is allowed.
*
* @since 4.2.3
- * @since 5.0.0 Add support for `data-*` wildcard attributes.
+ * @since 5.0.0 Added support for `data-*` wildcard attributes.
*
* @param string $name The attribute name. Passed by reference. Returns empty string when not allowed.
* @param string $value The attribute value. Passed by reference. Returns a filtered value.
@@ -1214,7 +1225,9 @@
* Note: the attribute name should only contain `A-Za-z0-9_-` chars,
* double hyphens `--` are not accepted by WordPress.
*/
- if ( strpos( $name_low, 'data-' ) === 0 && ! empty( $allowed_attr['data-*'] ) && preg_match( '/^data(?:-[a-z0-9_]+)+$/', $name_low, $match ) ) {
+ if ( strpos( $name_low, 'data-' ) === 0 && ! empty( $allowed_attr['data-*'] )
+ && preg_match( '/^data(?:-[a-z0-9_]+)+$/', $name_low, $match )
+ ) {
/*
* Add the whole attribute name to the allowed attributes and set any restrictions
* for the `data-*` attribute values for the current element.
@@ -1596,6 +1609,28 @@
$ok = false;
}
break;
+
+ case 'values':
+ /*
+ * The values check is used when you want to make sure that the attribute
+ * has one of the given values.
+ */
+
+ if ( false === array_search( strtolower( $value ), $checkvalue, true ) ) {
+ $ok = false;
+ }
+ break;
+
+ case 'value_callback':
+ /*
+ * The value_callback check is used when you want to make sure that the attribute
+ * value is accepted by the callback function.
+ */
+
+ if ( ! call_user_func( $checkvalue, $value ) ) {
+ $ok = false;
+ }
+ break;
} // End switch.
return $ok;
@@ -1846,13 +1881,13 @@
* @since 5.5.0
*
* @global array $allowedentitynames
- * @global array $allowedxmlnamedentities
+ * @global array $allowedxmlentitynames
*
* @param array $matches preg_replace_callback() matches array.
* @return string Correctly encoded entity.
*/
function wp_kses_xml_named_entities( $matches ) {
- global $allowedentitynames, $allowedxmlnamedentities;
+ global $allowedentitynames, $allowedxmlentitynames;
if ( empty( $matches[1] ) ) {
return '';
@@ -1860,7 +1895,7 @@
$i = $matches[1];
- if ( in_array( $i, $allowedxmlnamedentities, true ) ) {
+ if ( in_array( $i, $allowedxmlentitynames, true ) ) {
return "&$i;";
} elseif ( in_array( $i, $allowedentitynames, true ) ) {
return html_entity_decode( "&$i;", ENT_HTML5 );
@@ -2028,6 +2063,33 @@
}
/**
+ * Sanitizes global styles user content removing unsafe rules.
+ *
+ * @since 5.9.0
+ *
+ * @param string $data Post content to filter.
+ * @return string Filtered post content with unsafe rules removed.
+ */
+function wp_filter_global_styles_post( $data ) {
+ $decoded_data = json_decode( wp_unslash( $data ), true );
+ $json_decoding_error = json_last_error();
+ if (
+ JSON_ERROR_NONE === $json_decoding_error &&
+ is_array( $decoded_data ) &&
+ isset( $decoded_data['isGlobalStylesUserThemeJSON'] ) &&
+ $decoded_data['isGlobalStylesUserThemeJSON']
+ ) {
+ unset( $decoded_data['isGlobalStylesUserThemeJSON'] );
+
+ $data_to_encode = WP_Theme_JSON::remove_insecure_properties( $decoded_data );
+
+ $data_to_encode['isGlobalStylesUserThemeJSON'] = true;
+ return wp_slash( wp_json_encode( $data_to_encode ) );
+ }
+ return $data;
+}
+
+/**
* Sanitizes content for allowed HTML tags for post content.
*
* Post content refers to the page contents of the 'post' type and not `$_POST`
@@ -2095,6 +2157,10 @@
add_filter( 'pre_comment_content', 'wp_filter_kses' );
}
+ // Global Styles filtering: Global Styles filters should be executed before normal post_kses HTML filters.
+ add_filter( 'content_save_pre', 'wp_filter_global_styles_post', 9 );
+ add_filter( 'content_filtered_save_pre', 'wp_filter_global_styles_post', 9 );
+
// Post filtering.
add_filter( 'content_save_pre', 'wp_filter_post_kses' );
add_filter( 'excerpt_save_pre', 'wp_filter_post_kses' );
@@ -2121,6 +2187,10 @@
remove_filter( 'pre_comment_content', 'wp_filter_post_kses' );
remove_filter( 'pre_comment_content', 'wp_filter_kses' );
+ // Global Styles filtering.
+ remove_filter( 'content_save_pre', 'wp_filter_global_styles_post', 9 );
+ remove_filter( 'content_filtered_save_pre', 'wp_filter_global_styles_post', 9 );
+
// Post filtering.
remove_filter( 'content_save_pre', 'wp_filter_post_kses' );
remove_filter( 'excerpt_save_pre', 'wp_filter_post_kses' );
@@ -2148,6 +2218,16 @@
* Filters an inline style attribute and removes disallowed rules.
*
* @since 2.8.1
+ * @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 `background-image`.
+ * @since 5.1.0 Added support for `text-transform`.
+ * @since 5.2.0 Added support for `background-position` and `grid-template-columns`.
+ * @since 5.3.0 Added support for `grid`, `flex` and `column` layout properties.
+ * Extend `background-*` support of individual properties.
+ * @since 5.3.1 Added support for gradient backgrounds.
+ * @since 5.7.1 Added support for `object-position`.
+ * @since 5.8.0 Added support for `calc()` and `var()` values.
*
* @param string $css A string of CSS rules.
* @param string $deprecated Not used.
@@ -2166,19 +2246,9 @@
$css_array = explode( ';', trim( $css ) );
/**
- * Filters list of allowed CSS attributes.
+ * Filters the list of allowed CSS attributes.
*
* @since 2.8.1
- * @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 `background-image`.
- * @since 5.1.0 Added support for `text-transform`.
- * @since 5.2.0 Added support for `background-position` and `grid-template-columns`.
- * @since 5.3.0 Added support for `grid`, `flex` and `column` layout properties.
- * Extend `background-*` support of individual properties.
- * @since 5.3.1 Added support for gradient backgrounds.
- * @since 5.7.1 Added support for `object-position`.
- * @since 5.8.0 Added support for `calc()` and `var()` values.
*
* @param string[] $attr Array of allowed CSS attributes.
*/
@@ -2204,16 +2274,24 @@
'border-right-width',
'border-bottom',
'border-bottom-color',
+ 'border-bottom-left-radius',
+ 'border-bottom-right-radius',
'border-bottom-style',
'border-bottom-width',
+ 'border-bottom-right-radius',
+ 'border-bottom-left-radius',
'border-left',
'border-left-color',
'border-left-style',
'border-left-width',
'border-top',
'border-top-color',
+ 'border-top-left-radius',
+ 'border-top-right-radius',
'border-top-style',
'border-top-width',
+ 'border-top-left-radius',
+ 'border-top-right-radius',
'border-spacing',
'border-collapse',
@@ -2228,6 +2306,7 @@
'column-width',
'color',
+ 'filter',
'font',
'font-family',
'font-size',
@@ -2411,7 +2490,7 @@
*/
$allow_css = apply_filters( 'safecss_filter_attr_allow_css', $allow_css, $css_test_string );
- // Only add the CSS part if it passes the regex check.
+ // Only add the CSS part if it passes the regex check.
if ( $allow_css ) {
if ( '' !== $css ) {
$css .= ';';
@@ -2429,7 +2508,9 @@
* Helper function to add global attributes to a tag in the allowed HTML list.
*
* @since 3.5.0
- * @since 5.0.0 Add support for `data-*` wildcard attributes.
+ * @since 5.0.0 Added support for `data-*` wildcard attributes.
+ * @since 6.0.0 Added `dir`, `lang`, and `xml:lang` to global attributes.
+ *
* @access private
* @ignore
*
@@ -2444,11 +2525,14 @@
'aria-labelledby' => true,
'aria-hidden' => true,
'class' => true,
+ 'data-*' => true,
+ 'dir' => true,
'id' => true,
+ 'lang' => true,
'style' => true,
'title' => true,
'role' => true,
- 'data-*' => true,
+ 'xml:lang' => true,
);
if ( true === $value ) {
@@ -2461,3 +2545,39 @@
return $value;
}
+
+/**
+ * Helper function to check if this is a safe PDF URL.
+ *
+ * @since 5.9.0
+ * @access private
+ * @ignore
+ *
+ * @param string $url The URL to check.
+ * @return bool True if the URL is safe, false otherwise.
+ */
+function _wp_kses_allow_pdf_objects( $url ) {
+ // We're not interested in URLs that contain query strings or fragments.
+ if ( str_contains( $url, '?' ) || str_contains( $url, '#' ) ) {
+ return false;
+ }
+
+ // If it doesn't have a PDF extension, it's not safe.
+ if ( ! str_ends_with( $url, '.pdf' ) ) {
+ return false;
+ }
+
+ // If the URL host matches the current site's media URL, it's safe.
+ $upload_info = wp_upload_dir( null, false );
+ $parsed_url = wp_parse_url( $upload_info['url'] );
+ $upload_host = isset( $parsed_url['host'] ) ? $parsed_url['host'] : '';
+ $upload_port = isset( $parsed_url['port'] ) ? ':' . $parsed_url['port'] : '';
+
+ if ( str_starts_with( $url, "http://$upload_host$upload_port/" )
+ || str_starts_with( $url, "https://$upload_host$upload_port/" )
+ ) {
+ return true;
+ }
+
+ return false;
+}