From a58274f3049dbc81ea92493de76e6524217c74f9 Mon Sep 17 00:00:00 2001 From: Khokan Sardar Date: Thu, 6 Aug 2026 19:02:42 +0530 Subject: [PATCH 1/3] HTML API: Allow raw text which cannot close its own element. `WP_HTML_Tag_Processor::set_modifiable_text()` rejected any content containing `` follows it, so text such as `` inside an XMP element, or `` inside a SCRIPT element with an unrecognized content type, is ordinary text and round-trips safely. Require that terminating character before rejecting the update. Fixes #65824. --- .../html-api/class-wp-html-tag-processor.php | 20 +++++-- .../wpHtmlTagProcessorModifiableText.php | 56 +++++++++++++++++++ 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/src/wp-includes/html-api/class-wp-html-tag-processor.php b/src/wp-includes/html-api/class-wp-html-tag-processor.php index 7ca5191a0f162..85020b0efedc0 100644 --- a/src/wp-includes/html-api/class-wp-html-tag-processor.php +++ b/src/wp-includes/html-api/class-wp-html-tag-processor.php @@ -4090,11 +4090,14 @@ public function set_modifiable_text( string $plaintext_content ): bool { * Because of this, content which could potentially modify the SCRIPT tag’s * HTML structure is rejected here. It’s the responsibility of calling code to * perform whatever semantic escaping is necessary to avoid problematic strings. + * + * A tag name ends only at one of the characters matched below, so text + * such as `` cannot change that structure and is safe to set. + * + * @link https://html.spec.whatwg.org/#script-data-end-tag-name-state + * @link https://html.spec.whatwg.org/#script-data-double-escape-start-state */ - if ( - false !== stripos( $plaintext_content, ']~i', $plaintext_content ) ) { _doing_it_wrong( __METHOD__, __( 'SCRIPT text with an unrecognized content type cannot contain a SCRIPT tag. Apply the escaping appropriate for the content type.' ), @@ -4114,7 +4117,14 @@ public function set_modifiable_text( string $plaintext_content ): bool { case 'NOFRAMES': case 'XMP': $tag_name = $this->get_tag(); - if ( false !== stripos( $plaintext_content, "` cannot close the element and is safe to set. + * + * @link https://html.spec.whatwg.org/#rawtext-end-tag-name-state + */ + if ( 1 === preg_match( "~]~i", $plaintext_content ) ) { _doing_it_wrong( __METHOD__, sprintf( diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessorModifiableText.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessorModifiableText.php index 589318daf3a70..4c11252596c14 100644 --- a/tests/phpunit/tests/html-api/wpHtmlTagProcessorModifiableText.php +++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessorModifiableText.php @@ -586,6 +586,7 @@ public function test_replaces_previous_processing_instruction_data_update(): voi * * @ticket 61617 * @ticket 62797 + * @ticket 65824 * * @dataProvider data_unallowed_modifiable_text_updates * @@ -640,6 +641,61 @@ public static function data_unallowed_modifiable_text_updates() { 'Non-JS SCRIPT with ' => array( '', 'Just a ' ), 'Non-JS SCRIPT with ', '', '' ), + 'Non-JS SCRIPT with ' => array( '', 'Just a ', '' ), ); } From 82247b03933bd8c4fe07167f1732427287bf9b85 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Fri, 7 Aug 2026 12:38:44 +0200 Subject: [PATCH 2/3] Use preg_quote for preg-interpolated variable --- src/wp-includes/html-api/class-wp-html-tag-processor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/html-api/class-wp-html-tag-processor.php b/src/wp-includes/html-api/class-wp-html-tag-processor.php index 85020b0efedc0..3874bf1c698d3 100644 --- a/src/wp-includes/html-api/class-wp-html-tag-processor.php +++ b/src/wp-includes/html-api/class-wp-html-tag-processor.php @@ -4124,7 +4124,7 @@ public function set_modifiable_text( string $plaintext_content ): bool { * * @link https://html.spec.whatwg.org/#rawtext-end-tag-name-state */ - if ( 1 === preg_match( "~]~i", $plaintext_content ) ) { + if ( 1 === preg_match( '~]~i', $plaintext_content ) ) { _doing_it_wrong( __METHOD__, sprintf( From 94181a7413add931d2b9e4ce853a8bfdbbe00fdf Mon Sep 17 00:00:00 2001 From: Khokan Sardar Date: Fri, 7 Aug 2026 20:43:08 +0530 Subject: [PATCH 3/3] HTML API: Use preg_quote() for the TEXTAREA/TITLE tag name interpolation. --- src/wp-includes/html-api/class-wp-html-tag-processor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/html-api/class-wp-html-tag-processor.php b/src/wp-includes/html-api/class-wp-html-tag-processor.php index 3874bf1c698d3..ce793900f4f41 100644 --- a/src/wp-includes/html-api/class-wp-html-tag-processor.php +++ b/src/wp-includes/html-api/class-wp-html-tag-processor.php @@ -4165,7 +4165,7 @@ static function ( $tag_match ) { case 'TEXTAREA': case 'TITLE': $plaintext_content = preg_replace_callback( - "~{$this->get_tag()})~i", + '~' . preg_quote( $this->get_tag(), '~' ) . ')~i', static function ( $tag_match ) { return "</{$tag_match['TAG_NAME']}"; },