} */
@@ -70,7 +71,7 @@ function appendToResult(rootNode, attrs, result) {
if (isString(node)) {
result.push(node);
} else if (node.nodeType === Node.TEXT_NODE) {
- result.push(node.textContent ?? '');
+ result.push(escapeHtml(node.textContent ?? ''));
} else if (isElement(node) && isApplicableNode(node)) {
appendOpenTag(node, allowedAttrs, result);
stack.push(`${node.tagName.toLowerCase()}>`);
@@ -108,7 +109,7 @@ function appendOpenTag(node, attrs, result) {
attrs.forEach((attr) => {
if (node.hasAttribute(attr)) {
- result.push(` ${attr}="${node.getAttribute(attr)}"`);
+ result.push(` ${attr}="${escapeHtml(node.getAttribute(attr))}"`);
}
});
diff --git a/test/unit/core/dom/test-get-html.js b/test/unit/core/dom/test-get-html.js
index 0e0ef311837f..a9421e742214 100644
--- a/test/unit/core/dom/test-get-html.js
+++ b/test/unit/core/dom/test-get-html.js
@@ -53,4 +53,21 @@ describes.sandboxed('DOM - getHtml', {}, () => {
const result = getHtml(window, '.no-such-class', ['class', 'id']);
expect(result).to.equal('');
});
+
+ it('should escape quotes in attribute values', () => {
+ element.innerHTML =
+ '';
+ const result = getHtml(window, '#wrapper', ['class', 'title']);
+ expect(result).to.not.include('onmouseover="evil()"');
+ expect(result).to.include('title="x" onmouseover="evil()"');
+ });
+
+ it('should escape markup in text content', () => {
+ element.innerHTML =
+ '<img src=x onerror=alert(1)>
';
+ const result = getHtml(window, '#wrapper', []);
+ expect(result).to.equal('<img src=x onerror=alert(1)>
');
+ });
});