3

I was under the impression that all I needed to do to make inline JSON safe was to break any closing </script> tags in strings, e.g. escape the / like <\/script>.

However I found a weird combination that still breaks my page. The text "Won't print" won't be output onto the page. The HTML comment alone is fine, the script tag alone is fine, but the combination of the two is lethal. Why is that?

<!DOCTYPE html>
Before
<script>"<script>"</script>
fine
<script>"<!--"</script>
still fine
<script>"<!--<a>"</script>
fine again
<script>"<!--<script>"</script>
Won't print

Will display as "Before fine still fine fine again". "Won't print" will be treated as part of the script tag, which will be treated as unclosed.

  • That depends on a lot of details. How do you escape? What does the function "do" do? – Ben Sep 3 '18 at 6:25
  • I don't think it depends on anything. do throws an error because it's not defined. You can copy that literal HTML into an index.html file and see the behavior. "Won't print" is missing because everything is collapsed into the last script tag. – Adam A Sep 3 '18 at 8:17
  • 1
    This is interesting parser behavior. However, can you give a concrete example how this would introduce an XSS flaw? You'll eventually have to close the script tag to get any contained JS to execute. – Arminius Sep 3 '18 at 11:19
  • Yeah sorry, my terminology might be off. You can't execute your own script, you can just break the page with user-supplied content if it ever gets printed in an inline script without escaping of script start tags. What would you call that? – Adam A Sep 4 '18 at 10:02
  • While <!-- is the starting comment delimiter for XML, there is no sign of --> Perhaps the parser waits for the ending tag and hence the broken page? – bradbury9 Sep 4 '18 at 12:16
2

The correct answer to this is "because the HTML parser in the spec says so".

From the normal "inside a script tag" state, An HTML comment start (<!--) puts the parser into an escaped state, and from that mode a script start tag (<script>) puts into into a double escaped state in which script closing tags (</script>) are ignored.

Why on Earth does it do this? Backwards compatibility for inserting code into browsers that didn't support JS. Chaals gives a great answer on https://github.com/w3c/html/issues/1617, and I'll show his example of what was once normal code here:

<script>
  <!--    //hide from non-JS browsers
  function doSomething() {
    var coolScript = "<script>" + theCodeICopied + "</script>";
    document.write(coolScript);
  }
  // And if you forget to close your comment here, things go funnny
  -->
</script>

So now we're stuck with this page-breaking vulnerability unless you escape both start AND end script tags.

  • 1
    Shouldn't it be //<!-- and //--> ?? otherwise the XML would be interpreted as javascript and raise JS errors – bradbury9 Sep 4 '18 at 12:19
0

Why does “<!--<script>” in a JS string cause an XSS vulnerability?

Extraneous Open Brackets:

Submitted by Franz Sedlmaier, this XSS vector could defeat certain detection engines that work by first using matching pairs of open and close angle brackets and then by doing a comparison of the tag inside, instead of a more efficient algorythm like Boyer-Moore that looks for entire string matches of the open angle bracket and associated tag (post de-obfuscation, of course). The double slash comments out the ending extraneous bracket to supress a JavaScript error:

<<SCRIPT>alert("XSS");//<</SCRIPT>

Also see the next example at that link: "No closing script tags", having invalid code like that is incorrect. If that were the whole page and it contained nothing else then there wouldn't be an XSS vulnerability nor would anything be displayed. You are opening a comment and terminating it with an EOF, that is why nothing is printed. A do loop will always be executed at least once, even if the condition is false, because the code block is executed before the condition is tested; it will execute everything up to a while and either loop or terminate the loop.

  • Appreciate the link. What you'd said about the page is not true though - copying that into an HTML file prints exactly what I said it would into Chrome or Firefox. I should remove the "do" because it's just invalid/irrelevant junk. It doesn't have any affect on the HTML parsing. – Adam A Sep 3 '18 at 8:19
  • Could you quote the specific sentence that you disagree with. Copying that into a file starts a comment and terminates it with an EOF. We need a longer example if you don't want us to guess what comes afterwards. – Rob Sep 3 '18 at 8:23
  • It doesn't start a comment that ends with an EOF. The browser interprets it all as being content in the <script> tag. Here's an image showing something actually treated as a comment vs how this gets treated . Left is editor, right is dev tools monosnap.com/image/pFZPhfhLFiCAbswIuq4PWCCLl866NQ.png – Adam A Sep 3 '18 at 8:44
  • 1
    FWIW, you're onto something. The parser for <script> in HTML puts it into an escaped state w3.org/TR/html52/syntax.html#script-data-state. The HTML comment puts it into an escaped state (what?!) and the following <script> puts it into a double escaped state w3.org/TR/html52/… which cancels the next </script> – Adam A Sep 3 '18 at 9:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.