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..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
@@ -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, "{$tag_name}" ) ) {
+
+ /*
+ * A tag name ends only at one of the characters matched below, so text
+ * such as `` cannot close the element and is safe to set.
+ *
+ * @link https://html.spec.whatwg.org/#rawtext-end-tag-name-state
+ */
+ if ( 1 === preg_match( '~' . preg_quote( $tag_name, '~' ) . '[ \t\f\r\n/>]~i', $plaintext_content ) ) {
_doing_it_wrong(
__METHOD__,
sprintf(
@@ -4155,7 +4165,7 @@ static function ( $tag_match ) {
case 'TEXTAREA':
case 'TITLE':
$plaintext_content = preg_replace_callback(
- "~(?P{$this->get_tag()})~i",
+ '~(?P' . preg_quote( $this->get_tag(), '~' ) . ')~i',
static function ( $tag_match ) {
return "</{$tag_match['TAG_NAME']}";
},
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 ', '' ),
);
}