diff --git a/lib/NodeUtils.js b/lib/NodeUtils.js index a0a4962..7900a99 100644 --- a/lib/NodeUtils.js +++ b/lib/NodeUtils.js @@ -309,7 +309,13 @@ function serializeOne(kid, parent) { s += ''; break; case 7: //PROCESSING_INSTRUCTION_NODE - const content = escapeProcessingInstructionContent(kid.data); + let content = escapeProcessingInstructionContent(kid.data); + if (content.includes(''; break; case 10: //DOCUMENT_TYPE_NODE diff --git a/test/domino.js b/test/domino.js index 916e09d..8122768 100644 --- a/test/domino.js +++ b/test/domino.js @@ -1556,3 +1556,45 @@ exports.worksWithBase64DataImages = function () { 'iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII);">' ); }; + +exports.processingInstructionClosingTagEscapedInNoscript = function () { + // A processing-instruction payload that begins with a fallback raw-content + // closing tag (e.g. ` + // element early in the receiving browser (RAWTEXT) and the sibling + // is re-parsed as live HTML. + // Regression for angular/angular#70146: the fc7e40a (#70050) and e0779df + // (#70055) fixes escaped element/text/comment branches of serializeOne() + // but the PROCESSING_INSTRUCTION_NODE branch (case 7) never called + // fallbackRawContentTags(), and escapeProcessingInstructionContent() + // only escapes `>` (leaving `<` alone). + const document = domino.createDocument(''); + const noscript = document.createElement('noscript'); + noscript.appendChild(document.createProcessingInstruction('x', '' + ); + // The PI payload must not leak an unescaped closing-tag prefix. + html.should.not.containEql(''); + html.should.not.containEql('