From 2c3205bb843197cb94923958873fc27e3e991253 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Mon, 1 Nov 2021 02:13:56 +0000 Subject: [PATCH] KSES: Add options for restricting tags based upon their attributes. This change adds two now attribute-related config options to KSES: - 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. Included with this change is an implementation of these options, allowing the `` tag to be stored in posts, but only when it has a `type` attribute set to `application/pdf`. Props pento, swissspidy, peterwilsoncc, dd32, jorbin. Fixes #54261. Built from https://develop.svn.wordpress.org/trunk@51963 git-svn-id: http://core.svn.wordpress.org/trunk@51552 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/kses.php | 50 +++++++++++++++++++++++++++++++++++++++++ wp-includes/version.php | 2 +- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/wp-includes/kses.php b/wp-includes/kses.php index 0b24a1ba0c..3a7f99dd1a 100644 --- a/wp-includes/kses.php +++ b/wp-includes/kses.php @@ -271,6 +271,13 @@ if ( ! CUSTOM_TAGS ) { 'lang' => true, 'xml:lang' => true, ), + 'object' => array( + 'data' => true, + 'type' => array( + 'required' => true, + 'values' => array( 'application/pdf' ), + ), + ), 'p' => array( 'align' => true, 'dir' => true, @@ -1165,15 +1172,47 @@ function wp_kses_attr( $element, $attr, $allowed_html, $allowed_protocols ) { // Split it. $attrarr = wp_kses_hair( $attr, $allowed_protocols ); + // 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 ); @@ -1600,6 +1639,17 @@ function wp_kses_check_attr_val( $value, $vless, $checkname, $checkvalue ) { $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; } // End switch. return $ok; diff --git a/wp-includes/version.php b/wp-includes/version.php index a3290a7b8b..bf045dec68 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '5.9-alpha-51962'; +$wp_version = '5.9-alpha-51963'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.