From e4bbc6baa6616c7ea751bfd90d56152e95492ebd Mon Sep 17 00:00:00 2001
From: "C. Scott Ananian" <cscott@cscott.net>
Date: Tue, 14 Oct 2025 13:05:33 -0400
Subject: [PATCH] Sanitizer: disallow underscore and wide underscore in data-*
 attribute names

Also add wide underscore to the set of characters encoded in
attributes to ensure that Japenese double-underscore magic words
(which can begin with a double-wide underscore, U+FF3F) don't bypass
these protections.
When encountering two underscores in attribute values, escape both of
them, so magic words that start with double underscores but don't end
with them are not replaced.

Bug: T407131
Change-Id: I351edf35b965ac3cc9e50e47649efd88d238b2c2
Co-Authored-By: SomeRandomDeveloper <thisisnotmyname275@gmail.com>
---
 includes/parser/Sanitizer.php | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/includes/parser/Sanitizer.php b/includes/parser/Sanitizer.php
index 71a7a96bc6b..934f4029ad3 100644
--- a/includes/parser/Sanitizer.php
+++ b/includes/parser/Sanitizer.php
@@ -501,8 +501,10 @@ class Sanitizer {
 			# * Ensure attribute name will be accepted by the HTML
 			#   parser; see
 			#   https://github.com/whatwg/dom/issues/849#issuecomment-1007541209
+			# * Underscore and double-wide underscore (U+FF3F) is disallowed
+			#   here (but not in Parsoid): T407131
 			if ( (
-				!preg_match( '|^data-[^:= \t\r\n/>\0]*$|i', $attribute ) &&
+				!preg_match( '|^data-[^:= \t\r\n/>\0_＿]*$|i', $attribute ) &&
 				!array_key_exists( $attribute, $allowed )
 			) || self::isReservedDataAttribute( $attribute ) ) {
 				continue;
@@ -852,7 +854,8 @@ class Sanitizer {
 			'RFC'  => '&#82;FC',
 			'PMID' => '&#80;MID',
 			'|'    => '&#124;',
-			'__'   => '&#95;_',
+			'__'    => '&#95;&#95;',
+			'＿＿'    => '&#xFF3F;&#xFF3F;', // Japanese magic words
 		] );
 
 		# Stupid hack
-- 
2.51.0

