3 namespace Drupal\Tests\editor\Unit\EditorXssFilter;
5 use Drupal\editor\EditorXssFilter\Standard;
6 use Drupal\Tests\UnitTestCase;
7 use Drupal\filter\Plugin\FilterInterface;
10 * @coversDefaultClass \Drupal\editor\EditorXssFilter\Standard
13 class StandardTest extends UnitTestCase {
16 * The mocked text format configuration entity.
18 * @var \Drupal\filter\Entity\FilterFormat|\PHPUnit_Framework_MockObject_MockObject
22 protected function setUp() {
24 // Mock text format configuration entity object.
25 $this->format = $this->getMockBuilder('\Drupal\filter\Entity\FilterFormat')
26 ->disableOriginalConstructor()
28 $this->format->expects($this->any())
29 ->method('getFilterTypes')
30 ->will($this->returnValue([FilterInterface::TYPE_HTML_RESTRICTOR]));
41 $this->format->expects($this->any())
42 ->method('getHtmlRestrictions')
43 ->will($this->returnValue($restrictions));
47 * Provides test data for testFilterXss().
49 * @see \Drupal\Tests\editor\Unit\editor\EditorXssFilter\StandardTest::testFilterXss()
51 public function providerTestFilterXss() {
53 $data[] = ['<p>Hello, world!</p><unknown>Pink Fairy Armadillo</unknown>', '<p>Hello, world!</p><unknown>Pink Fairy Armadillo</unknown>'];
54 $data[] = ['<p style="color:red">Hello, world!</p><unknown>Pink Fairy Armadillo</unknown>', '<p>Hello, world!</p><unknown>Pink Fairy Armadillo</unknown>'];
55 $data[] = ['<p>Hello, world!</p><unknown>Pink Fairy Armadillo</unknown><script>alert("evil");</script>', '<p>Hello, world!</p><unknown>Pink Fairy Armadillo</unknown>alert("evil");'];
56 $data[] = ['<p>Hello, world!</p><unknown>Pink Fairy Armadillo</unknown><a href="javascript:alert(1)">test</a>', '<p>Hello, world!</p><unknown>Pink Fairy Armadillo</unknown><a href="alert(1)">test</a>'];
58 // All cases listed on https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
61 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#No_Filter_Evasion
62 $data[] = ['<SCRIPT SRC=http://ha.ckers.org/xss.js></SCRIPT>', ''];
64 // Image XSS using the JavaScript directive.
65 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Image_XSS_using_the_JavaScript_directive
66 $data[] = ['<IMG SRC="javascript:alert(\'XSS\');">', '<IMG src="alert('XSS');">'];
68 // No quotes and no semicolon.
69 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#No_quotes_and_no_semicolon
70 $data[] = ['<IMG SRC=javascript:alert(\'XSS\')>', '<IMG>'];
72 // Case insensitive XSS attack vector.
73 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Case_insensitive_XSS_attack_vector
74 $data[] = ['<IMG SRC=JaVaScRiPt:alert(\'XSS\')>', '<IMG>'];
77 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#HTML_entities
78 $data[] = ['<IMG SRC=javascript:alert("XSS")>', '<IMG>'];
80 // Grave accent obfuscation.
81 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Grave_accent_obfuscation
82 $data[] = ['<IMG SRC=`javascript:alert("RSnake says, \'XSS\'")`>', '<IMG>'];
85 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Malformed_A_tags
86 $data[] = ['<a onmouseover="alert(document.cookie)">xxs link</a>', '<a>xxs link</a>'];
87 $data[] = ['<a onmouseover=alert(document.cookie)>xxs link</a>', '<a>xxs link</a>'];
89 // Malformed IMG tags.
90 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Malformed_IMG_tags
91 $data[] = ['<IMG """><SCRIPT>alert("XSS")</SCRIPT>">', '<IMG>alert("XSS")">'];
94 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#fromCharCode
95 $data[] = ['<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>', '<IMG src="alert(String.fromCharCode(88,83,83))">'];
97 // Default SRC tag to get past filters that check SRC domain.
98 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Default_SRC_tag_to_get_past_filters_that_check_SRC_domain
99 $data[] = ['<IMG SRC=# onmouseover="alert(\'xxs\')">', '<IMG src="#">'];
101 // Default SRC tag by leaving it empty.
102 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Default_SRC_tag_by_leaving_it_empty
103 $data[] = ['<IMG SRC= onmouseover="alert(\'xxs\')">', '<IMG nmouseover="alert('xxs')">'];
105 // Default SRC tag by leaving it out entirely.
106 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Default_SRC_tag_by_leaving_it_out_entirely
107 $data[] = ['<IMG onmouseover="alert(\'xxs\')">', '<IMG>'];
109 // Decimal HTML character references.
110 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Decimal_HTML_character_references
111 $data[] = ['<IMG SRC=javascript:alert('XSS')>', '<IMG src="alert('XSS')">'];
113 // Decimal HTML character references without trailing semicolons.
114 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Decimal_HTML_character_references_without_trailing_semicolons
115 $data[] = ['<IMG SRC=javascript:alert('XSS')>', '<IMG src="&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041">'];
117 // Hexadecimal HTML character references without trailing semicolons.
118 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Hexadecimal_HTML_character_references_without_trailing_semicolons
119 $data[] = ['<IMG SRC=javascript:alert('XSS')>', '<IMG src="&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29">'];
122 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Embedded_tab
123 $data[] = ['<IMG SRC="jav ascript:alert(\'XSS\');">', '<IMG src="alert('XSS');">'];
125 // Embedded Encoded tab.
126 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Embedded_Encoded_tab
127 $data[] = ['<IMG SRC="jav	ascript:alert(\'XSS\');">', '<IMG src="alert('XSS');">'];
129 // Embedded newline to break up XSS.
130 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Embedded_newline_to_break_up_XSS
131 $data[] = ['<IMG SRC="jav
ascript:alert(\'XSS\');">', '<IMG src="alert('XSS');">'];
133 // Embedded carriage return to break up XSS.
134 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Embedded_carriage_return_to_break_up_XSS
135 $data[] = ['<IMG SRC="jav
ascript:alert(\'XSS\');">', '<IMG src="alert('XSS');">'];
137 // Null breaks up JavaScript directive.
138 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Null_breaks_up_JavaScript_directive
139 $data[] = ["<IMG SRC=java\0script:alert(\"XSS\")>", '<IMG>'];
141 // Spaces and meta chars before the JavaScript in images for XSS.
142 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Spaces_and_meta_chars_before_the_JavaScript_in_images_for_XSS
143 // @fixme This dataset currently fails under 5.4 because of
144 // https://www.drupal.org/node/1210798. Restore after it's fixed.
145 if (version_compare(PHP_VERSION, '5.4.0', '<')) {
146 $data[] = ['<IMG SRC="  javascript:alert(\'XSS\');">', '<IMG src="alert('XSS');">'];
149 // Non-alpha-non-digit XSS.
150 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Non-alpha-non-digit_XSS
151 $data[] = ['<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>', ''];
152 $data[] = ['<BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=alert("XSS")>', '<BODY>'];
153 $data[] = ['<SCRIPT/SRC="http://ha.ckers.org/xss.js"></SCRIPT>', ''];
155 // Extraneous open brackets.
156 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Extraneous_open_brackets
157 $data[] = ['<<SCRIPT>alert("XSS");//<</SCRIPT>', '<alert("XSS");//<'];
159 // No closing script tags.
160 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#No_closing_script_tags
161 $data[] = ['<SCRIPT SRC=http://ha.ckers.org/xss.js?< B >', ''];
163 // Protocol resolution in script tags.
164 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Protocol_resolution_in_script_tags
165 $data[] = ['<SCRIPT SRC=//ha.ckers.org/.j>', ''];
167 // Half open HTML/JavaScript XSS vector.
168 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Half_open_HTML.2FJavaScript_XSS_vector
169 $data[] = ['<IMG SRC="javascript:alert(\'XSS\')"', '<IMG src="alert('XSS')">'];
171 // Double open angle brackets.
172 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Double_open_angle_brackets
173 // @see http://ha.ckers.org/blog/20060611/hotbot-xss-vulnerability/ to
174 // understand why this is a vulnerability.
175 $data[] = ['<iframe src=http://ha.ckers.org/scriptlet.html <', '<iframe src="http://ha.ckers.org/scriptlet.html">'];
177 // Escaping JavaScript escapes.
178 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Escaping_JavaScript_escapes
179 // This one is irrelevant for Drupal; we *never* output any JavaScript code
180 // that depends on the URL's query string.
183 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#End_title_tag
184 $data[] = ['</TITLE><SCRIPT>alert("XSS");</SCRIPT>', '</TITLE>alert("XSS");'];
187 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#INPUT_image
188 $data[] = ['<INPUT TYPE="IMAGE" SRC="javascript:alert(\'XSS\');">', '<INPUT type="IMAGE" src="alert('XSS');">'];
191 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#BODY_image
192 $data[] = ['<BODY BACKGROUND="javascript:alert(\'XSS\')">', '<BODY background="alert('XSS')">'];
195 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#IMG_Dynsrc
196 $data[] = ['<IMG DYNSRC="javascript:alert(\'XSS\')">', '<IMG dynsrc="alert('XSS')">'];
199 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#IMG_lowsrc
200 $data[] = ['<IMG LOWSRC="javascript:alert(\'XSS\')">', '<IMG lowsrc="alert('XSS')">'];
203 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#List-style-image
204 $data[] = ['<STYLE>li {list-style-image: url("javascript:alert(\'XSS\')");}</STYLE><UL><LI>XSS</br>', 'li {list-style-image: url("javascript:alert(\'XSS\')");}<UL><LI>XSS</br>'];
206 // VBscript in an image.
207 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#VBscript_in_an_image
208 $data[] = ['<IMG SRC=\'vbscript:msgbox("XSS")\'>', '<IMG src=\'msgbox("XSS")\'>'];
210 // Livescript (older versions of Netscape only).
211 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Livescript_.28older_versions_of_Netscape_only.29
212 $data[] = ['<IMG SRC="livescript:[code]">', '<IMG src="[code]">'];
215 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#BODY_tag
216 $data[] = ['<BODY ONLOAD=alert(\'XSS\')>', '<BODY>'];
219 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Event_Handlers
228 'onBeforeDeactivate',
296 'onReadyStateChange',
325 foreach ($events as $event) {
326 $data[] = ['<p ' . $event . '="javascript:alert(\'XSS\');">Dangerous llama!</p>', '<p>Dangerous llama!</p>'];
330 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#BGSOUND
331 $data[] = ['<BGSOUND SRC="javascript:alert(\'XSS\');">', '<BGSOUND src="alert('XSS');">'];
333 // & JavaScript includes.
334 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#.26_JavaScript_includes
335 $data[] = ['<BR SIZE="&{alert(\'XSS\')}">', '<BR size="">'];
338 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#STYLE_sheet
339 $data[] = ['<LINK REL="stylesheet" HREF="javascript:alert(\'XSS\');">', ''];
341 // Remote style sheet.
342 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Remote_style_sheet
343 $data[] = ['<LINK REL="stylesheet" HREF="http://ha.ckers.org/xss.css">', ''];
345 // Remote style sheet part 2.
346 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Remote_style_sheet_part_2
347 $data[] = ['<STYLE>@import\'http://ha.ckers.org/xss.css\';</STYLE>', '@import\'http://ha.ckers.org/xss.css\';'];
349 // Remote style sheet part 3.
350 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Remote_style_sheet_part_3
351 $data[] = ['<META HTTP-EQUIV="Link" Content="<http://ha.ckers.org/xss.css>; REL=stylesheet">', '<META http-equiv="Link">; REL=stylesheet">'];
353 // Remote style sheet part 4.
354 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Remote_style_sheet_part_4
355 $data[] = ['<STYLE>BODY{-moz-binding:url("http://ha.ckers.org/xssmoz.xml#xss")}</STYLE>', 'BODY{-moz-binding:url("http://ha.ckers.org/xssmoz.xml#xss")}'];
357 // STYLE tags with broken up JavaScript for XSS.
358 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#STYLE_tags_with_broken_up_JavaScript_for_XSS
359 $data[] = ['<STYLE>@im\port\'\ja\vasc\ript:alert("XSS")\';</STYLE>', '@im\port\'\ja\vasc\ript:alert("XSS")\';'];
361 // STYLE attribute using a comment to break up expression.
362 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#STYLE_attribute_using_a_comment_to_break_up_expression
363 $data[] = ['<IMG STYLE="xss:expr/*XSS*/ession(alert(\'XSS\'))">', '<IMG>'];
365 // IMG STYLE with expression.
366 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#IMG_STYLE_with_expression
367 $data[] = ['exp/*<A STYLE=\'no\xss:noxss("*//*");
368 xss:ex/*XSS*//*/*/pression(alert("XSS"))\'>', 'exp/*<A>'];
370 // STYLE tag (Older versions of Netscape only).
371 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#STYLE_tag_.28Older_versions_of_Netscape_only.29
372 $data[] = ['<STYLE TYPE="text/javascript">alert(\'XSS\');</STYLE>', 'alert(\'XSS\');'];
374 // STYLE tag using background-image.
375 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#STYLE_tag_using_background-image
376 $data[] = ['<STYLE>.XSS{background-image:url("javascript:alert(\'XSS\')");}</STYLE><A CLASS=XSS></A>', '.XSS{background-image:url("javascript:alert(\'XSS\')");}<A class="XSS"></A>'];
378 // STYLE tag using background.
379 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#STYLE_tag_using_background
380 $data[] = ['<STYLE type="text/css">BODY{background:url("javascript:alert(\'XSS\')")}</STYLE>', 'BODY{background:url("javascript:alert(\'XSS\')")}'];
382 // Anonymous HTML with STYLE attribute.
383 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Anonymous_HTML_with_STYLE_attribute
384 $data[] = ['<XSS STYLE="xss:expression(alert(\'XSS\'))">', '<XSS>'];
387 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Local_htc_file
388 $data[] = ['<XSS STYLE="behavior: url(xss.htc);">', '<XSS>'];
390 // US-ASCII encoding.
391 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#US-ASCII_encoding
392 // This one is irrelevant for Drupal; Drupal *always* outputs UTF-8.
395 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#META
396 $data[] = ['<META HTTP-EQUIV="refresh" CONTENT="0;url=javascript:alert(\'XSS\');">', '<META http-equiv="refresh" content="alert('XSS');">'];
399 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#META_using_data
400 $data[] = ['<META HTTP-EQUIV="refresh" CONTENT="0;url=data:text/html base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K">', '<META http-equiv="refresh" content="text/html base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K">'];
402 // META with additional URL parameter
403 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#META
404 $data[] = ['<META HTTP-EQUIV="refresh" CONTENT="0; URL=http://;URL=javascript:alert(\'XSS\');">', '<META http-equiv="refresh" content="//;URL=javascript:alert('XSS');">'];
407 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#IFRAME
408 $data[] = ['<IFRAME SRC="javascript:alert(\'XSS\');"></IFRAME>', '<IFRAME src="alert('XSS');"></IFRAME>'];
410 // IFRAME Event based.
411 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#IFRAME_Event_based
412 $data[] = ['<IFRAME SRC=# onmouseover="alert(document.cookie)"></IFRAME>', '<IFRAME src="#"></IFRAME>'];
415 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#FRAME
416 $data[] = ['<FRAMESET><FRAME SRC="javascript:alert(\'XSS\');"></FRAMESET>', '<FRAMESET><FRAME src="alert('XSS');"></FRAMESET>'];
419 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#TABLE
420 $data[] = ['<TABLE BACKGROUND="javascript:alert(\'XSS\')">', '<TABLE background="alert('XSS')">'];
423 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#TD
424 $data[] = ['<TABLE><TD BACKGROUND="javascript:alert(\'XSS\')">', '<TABLE><TD background="alert('XSS')">'];
426 // DIV background-image.
427 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#DIV_background-image
428 $data[] = ['<DIV STYLE="background-image: url(javascript:alert(\'XSS\'))">', '<DIV>'];
430 // DIV background-image with unicoded XSS exploit.
431 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#DIV_background-image_with_unicoded_XSS_exploit
432 $data[] = ['<DIV STYLE="background-image:\0075\0072\006C\0028\'\006a\0061\0076\0061\0073\0063\0072\0069\0070\0074\003a\0061\006c\0065\0072\0074\0028.1027\0058.1053\0053\0027\0029\'\0029">', '<DIV>'];
434 // DIV background-image plus extra characters.
435 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#DIV_background-image_plus_extra_characters
436 $data[] = ['<DIV STYLE="background-image: url(javascript:alert(\'XSS\'))">', '<DIV>'];
439 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#DIV_expression
440 $data[] = ['<DIV STYLE="width: expression(alert(\'XSS\'));">', '<DIV>'];
442 // Downlevel-Hidden block.
443 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Downlevel-Hidden_block
444 $data[] = ['<!--[if gte IE 4]>
445 <SCRIPT>alert(\'XSS\');</SCRIPT>
446 <![endif]-->', "\n alert('XSS');\n "];
449 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#BASE_tag
450 $data[] = ['<BASE HREF="javascript:alert(\'XSS\');//">', '<BASE href="alert('XSS');//">'];
453 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#OBJECT_tag
454 $data[] = ['<OBJECT TYPE="text/x-scriptlet" DATA="http://ha.ckers.org/scriptlet.html"></OBJECT>', ''];
456 // Using an EMBED tag you can embed a Flash movie that contains XSS.
457 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Using_an_EMBED_tag_you_can_embed_a_Flash_movie_that_contains_XSS
458 $data[] = ['<EMBED SRC="http://ha.ckers.org/xss.swf" AllowScriptAccess="always"></EMBED>', ''];
460 // You can EMBED SVG which can contain your XSS vector.
461 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#You_can_EMBED_SVG_which_can_contain_your_XSS_vector
462 $data[] = ['<EMBED SRC="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==" type="image/svg+xml" AllowScriptAccess="always"></EMBED>', ''];
464 // XML data island with CDATA obfuscation.
465 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#XML_data_island_with_CDATA_obfuscation
466 $data[] = ['<XML ID="xss"><I><B><IMG SRC="javas<!-- -->cript:alert(\'XSS\')"></B></I></XML><SPAN DATASRC="#xss" DATAFLD="B" DATAFORMATAS="HTML"></SPAN>', '<XML id="xss"><I><B><IMG>cript:alert(\'XSS\')"></B></I></XML><SPAN datasrc="#xss" datafld="B" dataformatas="HTML"></SPAN>'];
468 // Locally hosted XML with embedded JavaScript that is generated using an XML data island.
469 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Locally_hosted_XML_with_embedded_JavaScript_that_is_generated_using_an_XML_data_island
470 // This one is irrelevant for Drupal; Drupal disallows XML uploads by
474 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#HTML.2BTIME_in_XML
475 $data[] = ['<?xml:namespace prefix="t" ns="urn:schemas-microsoft-com:time"><?import namespace="t" implementation="#default#time2"><t:set attributeName="innerHTML" to="XSS<SCRIPT DEFER>alert("XSS")</SCRIPT>">', '<?xml:namespace prefix="t" ns="urn:schemas-microsoft-com:time"><?import namespace="t" implementation="#default#time2"><t set attributename="innerHTML">alert("XSS")">'];
477 // Assuming you can only fit in a few characters and it filters against ".js".
478 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Assuming_you_can_only_fit_in_a_few_characters_and_it_filters_against_.22.js.22
479 $data[] = ['<SCRIPT SRC="http://ha.ckers.org/xss.jpg"></SCRIPT>', ''];
481 // IMG Embedded commands.
482 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#IMG_Embedded_commands
483 // This one is irrelevant for Drupal; this is actually a CSRF, for which
484 // Drupal has CSRF protection. See https://www.drupal.org/node/178896.
486 // Cookie manipulation.
487 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Cookie_manipulation
488 $data[] = ['<META HTTP-EQUIV="Set-Cookie" Content="USERID=<SCRIPT>alert(\'XSS\')</SCRIPT>">', '<META http-equiv="Set-Cookie">alert(\'XSS\')">'];
491 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#UTF-7_encoding
492 // This one is irrelevant for Drupal; Drupal *always* outputs UTF-8.
494 // XSS using HTML quote encapsulation.
495 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#XSS_using_HTML_quote_encapsulation
496 $data[] = ['<SCRIPT a=">" SRC="http://ha.ckers.org/xss.js"></SCRIPT>', '" SRC="http://ha.ckers.org/xss.js">'];
497 $data[] = ['<SCRIPT =">" SRC="http://ha.ckers.org/xss.js"></SCRIPT>', '" SRC="http://ha.ckers.org/xss.js">'];
498 $data[] = ['<SCRIPT a=">" \'\' SRC="http://ha.ckers.org/xss.js"></SCRIPT>', '" \'\' SRC="http://ha.ckers.org/xss.js">'];
499 $data[] = ['<SCRIPT "a=\'>\'" SRC="http://ha.ckers.org/xss.js"></SCRIPT>', '\'" SRC="http://ha.ckers.org/xss.js">'];
500 $data[] = ['<SCRIPT a=`>` SRC="http://ha.ckers.org/xss.js"></SCRIPT>', '` SRC="http://ha.ckers.org/xss.js">'];
501 $data[] = ['<SCRIPT a=">\'>" SRC="http://ha.ckers.org/xss.js"></SCRIPT>', '\'>" SRC="http://ha.ckers.org/xss.js">'];
502 $data[] = ['<SCRIPT>document.write("<SCRI");</SCRIPT>PT SRC="http://ha.ckers.org/xss.js"></SCRIPT>', 'document.write("<SCRI>PT SRC="http://ha.ckers.org/xss.js">'];
504 // URL string evasion.
505 // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#URL_string_evasion
506 // This one is irrelevant for Drupal; Drupal doesn't forbid linking to some
507 // sites, it only forbids linking to any protocols other than those that are
510 // Test XSS filtering on data-attributes.
511 // @see \Drupal\editor\EditorXssFilter::filterXssDataAttributes()
513 // The following two test cases verify that XSS attack vectors are filtered.
514 $data[] = ['<img src="butterfly.jpg" data-caption="<script>alert();</script>" />', '<img src="butterfly.jpg" data-caption="alert();" />'];
515 $data[] = ['<img src="butterfly.jpg" data-caption="<EMBED SRC="http://ha.ckers.org/xss.swf" AllowScriptAccess="always"></EMBED>" />', '<img src="butterfly.jpg" data-caption="" />'];
517 // When including HTML-tags as visible content, they are double-escaped.
518 // This test case ensures that we leave that content unchanged.
519 $data[] = ['<img src="butterfly.jpg" data-caption="&lt;script&gt;alert();&lt;/script&gt;" />', '<img src="butterfly.jpg" data-caption="&lt;script&gt;alert();&lt;/script&gt;" />'];
525 * Tests the method for filtering XSS.
527 * @param string $input
529 * @param string $expected_output
530 * The expected output.
532 * @dataProvider providerTestFilterXss
534 public function testFilterXss($input, $expected_output) {
535 $output = Standard::filterXss($input, $this->format);
536 $this->assertSame($expected_output, $output);
540 * Tests removing disallowed tags and XSS prevention.
542 * \Drupal\Component\Utility\Xss::filter() has the ability to run in blacklist
543 * mode, in which it still applies the exact same filtering, with one
544 * exception: it no longer works with a list of allowed tags, but with a list
545 * of disallowed tags.
547 * @param string $value
548 * The value to filter.
549 * @param string $expected
550 * The string that is expected to be missing.
551 * @param string $message
552 * The assertion message to display upon failure.
553 * @param array $disallowed_tags
554 * (optional) The disallowed HTML tags to be passed to \Drupal\Component\Utility\Xss::filter().
556 * @dataProvider providerTestBlackListMode
558 public function testBlacklistMode($value, $expected, $message, array $disallowed_tags) {
559 $value = Standard::filter($value, $disallowed_tags);
560 $this->assertSame($expected, $value, $message);
564 * Data provider for testBlacklistMode().
566 * @see testBlacklistMode()
569 * An array of arrays containing the following elements:
570 * - The value to filter.
571 * - The value to expect after filtering.
572 * - The assertion message.
573 * - (optional) The disallowed HTML tags to be passed to \Drupal\Component\Utility\Xss::filter().
575 public function providerTestBlackListMode() {
578 '<unknown style="visibility:hidden">Pink Fairy Armadillo</unknown><video src="gerenuk.mp4"><script>alert(0)</script>',
579 '<unknown>Pink Fairy Armadillo</unknown><video src="gerenuk.mp4">alert(0)',
580 'Disallow only the script tag',
584 '<unknown style="visibility:hidden">Pink Fairy Armadillo</unknown><video src="gerenuk.mp4"><script>alert(0)</script>',
585 '<unknown>Pink Fairy Armadillo</unknown>alert(0)',
586 'Disallow both the script and video tags',
589 // No real use case for this, but it is an edge case we must ensure works.
591 '<unknown style="visibility:hidden">Pink Fairy Armadillo</unknown><video src="gerenuk.mp4"><script>alert(0)</script>',
592 '<unknown>Pink Fairy Armadillo</unknown><video src="gerenuk.mp4"><script>alert(0)</script>',