Skip to content

Commit

Permalink
Merge pull request from GHSA-5fg8-2547-mr8q
Browse files Browse the repository at this point in the history
  • Loading branch information
karfau committed Jul 27, 2021
1 parent 9b92ff4 commit 7b4b743
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 11 deletions.
23 changes: 12 additions & 11 deletions lib/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,15 @@ function needNamespaceDefine(node, isHTML, visibleNamespaces) {
}
return true;
}
/**
* Well-formed constraint: No < in Attribute Values
* The replacement text of any entity referred to directly or indirectly in an attribute value must not contain a <.
* @see https://www.w3.org/TR/xml/#CleanAttrVals
* @see https://www.w3.org/TR/xml/#NT-AttValue
*/
function addSerializedAttribute(buf, qualifiedName, value) {
buf.push(' ', qualifiedName, '="', value.replace(/[<&"]/g,_xmlEncoder), '"')
}

function serializeToString(node,buf,isHTML,nodeFilter,visibleNamespaces){
if (!visibleNamespaces) {
Expand Down Expand Up @@ -1196,8 +1205,7 @@ function serializeToString(node,buf,isHTML,nodeFilter,visibleNamespaces){
if (needNamespaceDefine(attr,isHTML, visibleNamespaces)) {
var prefix = attr.prefix||'';
var uri = attr.namespaceURI;
var ns = prefix ? ' xmlns:' + prefix : " xmlns";
buf.push(ns, '="' , uri , '"');
addSerializedAttribute(buf, prefix ? 'xmlns:' + prefix : "xmlns", uri);
visibleNamespaces.push({ prefix: prefix, namespace:uri });
}
serializeToString(attr,buf,isHTML,nodeFilter,visibleNamespaces);
Expand All @@ -1207,8 +1215,7 @@ function serializeToString(node,buf,isHTML,nodeFilter,visibleNamespaces){
if (nodeName === prefixedNodeName && needNamespaceDefine(node, isHTML, visibleNamespaces)) {
var prefix = node.prefix||'';
var uri = node.namespaceURI;
var ns = prefix ? ' xmlns:' + prefix : " xmlns";
buf.push(ns, '="' , uri , '"');
addSerializedAttribute(buf, prefix ? 'xmlns:' + prefix : "xmlns", uri);
visibleNamespaces.push({ prefix: prefix, namespace:uri });
}

Expand Down Expand Up @@ -1247,13 +1254,7 @@ function serializeToString(node,buf,isHTML,nodeFilter,visibleNamespaces){
}
return;
case ATTRIBUTE_NODE:
/**
* Well-formedness constraint: No < in Attribute Values
* The replacement text of any entity referred to directly or indirectly in an attribute value must not contain a <.
* @see https://www.w3.org/TR/xml/#CleanAttrVals
* @see https://www.w3.org/TR/xml/#NT-AttValue
*/
return buf.push(' ', node.name, '="', node.value.replace(/[<&"]/g,_xmlEncoder), '"');
return addSerializedAttribute(buf, node.name, node.value);
case TEXT_NODE:
/**
* The ampersand character (&) and the left angle bracket (<) must not appear in their literal form,
Expand Down
19 changes: 19 additions & 0 deletions test/dom/serializer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,23 @@ describe('XML Serializer', () => {
)
})
})
describe('properly escapes attribute values', () => {
it('should escape special characters in namespace attributes', () => {
const input = `<xml xmlns='<&"' xmlns:attr='"&<'><test attr:test=""/></xml>`
const doc = new DOMParser().parseFromString(input, MIME_TYPE.XML_TEXT)

// in this case the explicit attribute nodes are serialized
expect(new XMLSerializer().serializeToString(doc)).toBe(
'<xml xmlns="&lt;&amp;&quot;" xmlns:attr="&quot;&amp;&lt;"><test attr:test=""/></xml>'
)

// in this case the namespace attributes are "inherited" from the parent,
// which is not serialized
expect(
new XMLSerializer().serializeToString(doc.documentElement.firstChild)
).toBe(
'<test xmlns:attr="&quot;&amp;&lt;" attr:test="" xmlns="&lt;&amp;&quot;"/>'
)
})
})
})

0 comments on commit 7b4b743

Please sign in to comment.