@@ -38,4 +38,51 @@ public function test_basic_render() {
3838 'Failed to properly render template. '
3939 );
4040 }
41+
42+ /**
43+ * Ensures that basic attacks on attribute names and values are blocked.
44+ *
45+ * @ticket 60229
46+ *
47+ * @covers WP_HTML::render
48+ */
49+ public function test_cannot_break_out_of_tag_with_malicious_attribute_name () {
50+ $ html = WP_HTML_Template::render (
51+ '<div class="</%class>" ...args> ' ,
52+ array (
53+ 'class ' => '"><script>alert("hi")</script> ' ,
54+ 'args ' => array (
55+ '"> double-quoted escape ' => 'busted! ' ,
56+ '> tag escape ' => 'busted! ' ,
57+ ),
58+ )
59+ );
60+
61+ // The output here should include an escaped `class` attribute and no others, also no other tags.
62+ $ processor = new WP_HTML_Tag_Processor ( $ html );
63+ $ processor ->next_tag ();
64+
65+ $ this ->assertSame (
66+ 'DIV ' ,
67+ $ processor ->get_tag (),
68+ "Expected to find DIV tag but found {$ processor ->get_tag ()} instead. "
69+ );
70+
71+ $ this ->assertSame (
72+ '"><script>alert("hi")</script> ' ,
73+ $ processor ->get_attribute ( 'class ' ),
74+ 'Should have found escaped `class` attribute. '
75+ );
76+
77+ $ this ->assertSame (
78+ array ( 'class ' ),
79+ $ processor ->get_attribute_names_with_prefix ( '' ),
80+ 'Should have set `class` attribute and no others. '
81+ );
82+
83+ $ this ->assertFalse (
84+ $ processor ->next_tag (),
85+ "Should not have found any other tags but found {$ processor ->get_tag ()} instead. "
86+ );
87+ }
4188}
0 commit comments