Edition for Web Developers — Last Updated 12 June 2026
APIs for dynamically inserting markup into the document interact with the parser, and thus their behavior varies depending on whether they are used with HTML documents (and the HTML parser) or XML documents (and the XML parser).
document = document.open()Causes the Document to be replaced in-place, as if it was a new
Document object, but reusing the previous object, which is then returned.
The resulting Document has an HTML parser associated with it, which can be given
data to parse using document.write().
The method has no effect if the Document is still being parsed.
Throws an "InvalidStateError" DOMException if the
Document is an XML document.
Throws an "InvalidStateError" DOMException if the
parser is currently executing a custom element constructor.
window = document.open(url, name, features)Works like the window.open() method.
document.close()Closes the input stream that was opened by the document.open() method.
Throws an "InvalidStateError" DOMException if the
Document is an XML document.
Throws an "InvalidStateError" DOMException if the
parser is currently executing a custom element constructor.
document.write()document.write(...text)In general, adds the given string(s) to the Document's input stream.
This method has very idiosyncratic behavior. In some cases, this method can
affect the state of the HTML parser while the parser is running, resulting in a DOM
that does not correspond to the source of the document (e.g. if the string written is the string
"<plaintext>" or "<!--"). In other cases,
the call can clear the current page first, as if document.open() had been called. In yet more cases, the method
is simply ignored, or throws an exception. User agents are explicitly allowed to avoid executing
script elements inserted via this method. And to make matters even worse, the
exact behavior of this method can in some cases be dependent on network latency, which can lead to failures that are very hard to debug. For all these reasons, use
of this method is strongly discouraged.
Throws an "InvalidStateError" DOMException when
invoked on XML documents.
Throws an "InvalidStateError" DOMException if the
parser is currently executing a custom element constructor.
This method performs no sanitization to remove potentially-dangerous elements
and attributes like script or event handler content attributes.
document.writeln()document.writeln(...text)Adds the given string(s) to the Document's input stream, followed by a newline
character. If necessary, calls the open() method
implicitly first.
This method has very idiosyncratic behavior. Use of this
method is strongly discouraged, for the same reasons as document.write().
Throws an "InvalidStateError" DOMException when
invoked on XML documents.
Throws an "InvalidStateError" DOMException if the
parser is currently executing a custom element constructor.
This method performs no sanitization to remove potentially-dangerous elements
and attributes like script or event handler content attributes.
Support in all current engines.
DOMParser interfaceThe DOMParser interface allows authors to create new Document objects
by parsing strings, as either HTML or XML.
parser = new DOMParser()Constructs a new DOMParser object.
document = parser.parseFromString(string, type)Parses string using either the HTML or XML parser, according to type,
and returns the resulting Document. type can be "text/html"
(which will invoke the HTML parser), or any of "text/xml",
"application/xml", "application/xhtml+xml", or
"image/svg+xml" (which will invoke the XML parser).
For the XML parser, if string cannot be parsed, then the returned
Document will contain elements describing the resulting error.
Note that script elements are not evaluated during parsing, and the resulting
document's encoding will always be
UTF-8. The document's URL will be
inherited from parser's relevant global object.
Values other than the above for type will cause a TypeError exception
to be thrown.
The design of DOMParser, as a class that needs to be constructed and
then have its parseFromString() method
called, is an unfortunate historical artifact. If we were designing this functionality today it
would be a standalone function. For parsing HTML, the modern alternative is Document.parseHTMLUnsafe().
This method performs no sanitization to remove potentially-dangerous elements
and attributes like script or event handler content attributes.
element.setHTML(html, options)Parses html using the HTML parser with options options, and replaces
the children of element with the result. element provides context for the
HTML parser. The parsed fragment is sanitized based on the
options's "sanitizer" member, and
unsafe content is removed.
shadowRoot.setHTML(html, options)Parses html using the HTML parser with options options, and replaces
the children of shadowRoot with the result. shadowRoot's host provides context for the HTML parser. The
parsed fragment is sanitized based on the options's
"sanitizer" member, and unsafe content is removed.
element.setHTMLUnsafe(html, options)Parses html using the HTML parser with options options, and replaces
the children of element with the result. element provides context for the
HTML parser. If the options dictionary contains a "sanitizer" member, it is used to
sanitize the parsed fragment before it is inserted into element. If the
options dictionary's "runScripts" member is true, scripts contained
in html will be executed immediately after the node tree is updated.
shadowRoot.setHTMLUnsafe(html, options)Parses html using the HTML parser with options options, and replaces
the children of shadowRoot with the result. shadowRoot's host provides context for the HTML parser. If the
options dictionary contains a "sanitizer" member, it is used to
sanitize the parsed fragment before it is inserted into shadowRoot. If
the options dictionary's "runScripts" member is true, scripts contained
in html will be executed immediately after the node tree is updated.
doc = Document.parseHTML(html, options)Parses html using the HTML parser with options options, and returns
a new Document containing the result. The resulting document is sanitized based on the options's "sanitizer" member, and unsafe content is removed.
doc = Document.parseHTMLUnsafe(html, options)Parses html using the HTML parser with options options, and returns the
resulting Document.
Note that script elements are not evaluated during parsing, and the resulting
document's encoding will always be
UTF-8. The document's URL will be
about:blank. If the options dictionary contains a "sanitizer" member, it is used to
sanitize the resulting DOM.
The methods with an Unsafe suffix perform no
sanitization to remove potentially-dangerous elements and attributes like script or
event handler content attributes.
html = element.getHTML({ serializableShadowRoots, shadowRoots })Returns the result of serializing element to HTML. Shadow roots within element are serialized according to the provided options:
If serializableShadowRoots is true, then all shadow roots marked as serializable are serialized.
If the shadowRoots array is provided, then all shadow roots specified in the array are serialized, regardless of whether or not they are marked as serializable.
If neither option is provided, then no shadow roots are serialized.
html = shadowRoot.getHTML({ serializableShadowRoots, shadowRoots })Returns the result of serializing shadowRoot to HTML, using its shadow host as the context element. Shadow roots within shadowRoot are serialized according to the provided options, as above.
innerHTML propertyThe innerHTML property has a number of outstanding issues
in the DOM Parsing and Serialization issue
tracker, documenting various problems with its specification.
element.innerHTMLReturns a fragment of HTML or XML that represents the element's contents.
In the case of an XML document, throws an "InvalidStateError"
DOMException if the element cannot be serialized to XML.
element.innerHTML = valueReplaces the contents of the element with nodes parsed from the given string.
In the case of an XML document, throws a "SyntaxError"
DOMException if the given string is not well-formed.
shadowRoot.innerHTMLReturns a fragment of HTML that represents the shadow roots's contents.
shadowRoot.innerHTML = valueReplaces the contents of the shadow root with nodes parsed from the given string.
These properties' setters perform no sanitization to remove
potentially-dangerous elements and attributes like script or event handler
content attributes.
outerHTML propertyThe outerHTML property has a number of outstanding issues
in the DOM Parsing and Serialization issue
tracker, documenting various problems with its specification.
element.outerHTMLReturns a fragment of HTML or XML that represents the element and its contents.
In the case of an XML document, throws an "InvalidStateError"
DOMException if the element cannot be serialized to XML.
element.outerHTML = valueReplaces the element with nodes parsed from the given string.
In the case of an XML document, throws a "SyntaxError"
DOMException if the given string is not well-formed.
Throws a "NoModificationAllowedError" DOMException if
the parent of the element is a Document.
This property's setter performs no sanitization to remove potentially-dangerous
elements and attributes like script or event handler content
attributes.
insertAdjacentHTML() methodThe insertAdjacentHTML()
method has a number of outstanding issues in the DOM Parsing and Serialization issue tracker, documenting various problems
with its specification.
element.insertAdjacentHTML(position, string)Parses string as HTML or XML and inserts the resulting nodes into the tree in the position given by the position argument, as follows:
beforebegin"afterbegin"beforeend"afterend"Throws a "SyntaxError" DOMException if the arguments
have invalid values (e.g., in the case of an XML document,
if the given string is not well-formed).
Throws a "NoModificationAllowedError" DOMException
if the given position isn't possible (e.g. inserting elements after the root element of a
Document).
This method performs no sanitization to remove potentially-dangerous elements
and attributes like script or event handler content attributes.
createContextualFragment()
methodThe createContextualFragment() method has a number
of outstanding issues in the DOM Parsing and Serialization issue tracker, documenting various problems
with its specification.
docFragment = range.createContextualFragment(string)Returns a DocumentFragment created from the markup string string using
range's start node as the context in
which fragment is parsed.
This method performs no sanitization to remove potentially-dangerous elements
and attributes like script or event handler content attributes.
XMLSerializer interfaceThe XMLSerializer interface has a number of outstanding issues in the
DOM Parsing and Serialization issue tracker, documenting various problems
with its specification. The remainder of DOM Parsing and Serialization will be
gradually upstreamed to this specification.
xmlSerializer = new XMLSerializer()Constructs a new XMLSerializer object.
string = xmlSerializer.serializeToString(root)Returns the result of serializing root to XML.
Throws an "InvalidStateError" DOMException if
root cannot be serialized to XML.
The design of XMLSerializer, as a class that needs to be constructed
and then have its serializeToString()
method called, is an unfortunate historical artifact. If we were designing this functionality
today it would be a standalone function.
Web applications often need to process untrusted HTML strings, such as when rendering user-generated content or using client-side templates. Safely inserting these strings into the DOM requires careful sanitization to prevent DOM-based cross-site scripting (XSS) attacks.
HTML sanitization provides a native mechanism for safely parsing and sanitizing HTML strings. By using the user agent's own HTML parser, they ensure the sanitized output accurately reflects how the browser will render the content, preventing script execution and mitigating advanced attacks such as script gadgets.
These APIs offer functionality to parse a string containing HTML into a DOM tree, and to filter the resulting tree according to a user-supplied configuration. The methods come in two main flavors: "safe" and "unsafe".
The "safe" methods will not generate any markup that executes script. That is, they are intended to be safe from XSS. The "unsafe" methods will parse and filter based on the provided configuration, but do not have the same safety guarantees by default.
Sanitizer interfaceconfig = sanitizer.get()Returns a copy of the sanitizer's configuration.
sanitizer.allowElement(element)Ensures that the sanitizer configuration allows the specified element.
sanitizer.removeElement(element)Ensures that the sanitizer configuration blocks the specified element.
sanitizer.replaceElementWithChildren(element)Configures the sanitizer to remove the specified element but keep its child nodes.
sanitizer.allowAttribute(attribute)Configures the sanitizer to allow the specified attribute globally.
sanitizer.removeAttribute(attribute)Configures the sanitizer to block the specified attribute globally.
sanitizer.allowProcessingInstruction(pi)Configures the sanitizer to allow the specified processing instruction.
sanitizer.removeProcessingInstruction(pi)Configures the sanitizer to block the specified processing instruction.
sanitizer.setComments(allow)Sets whether the sanitizer preserves comments.
sanitizer.setDataAttributes(allow)Sets whether the sanitizer preserves custom data attributes (e.g., data-*).
sanitizer.removeUnsafe()Modifies the configuration to automatically remove elements and attributes that are considered unsafe.
A Sanitizer object has an associated configuration,
which is a SanitizerConfig.
The new
Sanitizer(configuration) constructor steps are:
To configure a Sanitizer
sanitizer, given a dictionary configuration and a boolean
allowCommentsPIsAndDataAttributes:
Canonicalize the configuration configuration with allowCommentsPIsAndDataAttributes.
If configuration is not valid,
then throw a TypeError.
Set sanitizer's configuration to configuration.
To canonicalize the configuration SanitizerConfig configuration with a boolean allowCommentsPIsAndDataAttributes:
If neither configuration["elements"] nor configuration["removeElements"] exists, then set configuration["removeElements"] to an empty list.
If neither configuration["attributes"] nor configuration["removeAttributes"] exists, then set configuration["removeAttributes"] to an empty
list.
If neither configuration["processingInstructions"] nor
configuration["removeProcessingInstructions"]
exists:
If allowCommentsPIsAndDataAttributes is true, then set
configuration["removeProcessingInstructions"]
to an empty list.
Otherwise, set configuration["processingInstructions"] to an empty
list.
If configuration["elements"]
exists:
If configuration["removeElements"] exists, then set configuration["removeElements"] to the result of canonicalizing
configuration["removeElements"].
If configuration["attributes"] exists, then set configuration["attributes"] to the result of canonicalizing configuration["attributes"].
If configuration["removeAttributes"] exists, then set configuration["removeAttributes"] to the result of canonicalizing configuration["removeAttributes"].
If configuration["replaceWithChildrenElements"]
exists, then set configuration["replaceWithChildrenElements"] to
the result of canonicalizing
configuration["replaceWithChildrenElements"].
If configuration["processingInstructions"] exists, then set configuration["processingInstructions"] to the result
of canonicalizing
configuration["processingInstructions"].
If configuration["removeProcessingInstructions"]
exists, then set configuration["removeProcessingInstructions"]
to the result of canonicalizing
configuration["removeProcessingInstructions"].
If configuration["comments"]
does not exist, then set it to
allowCommentsPIsAndDataAttributes.
If configuration["attributes"] exists and configuration["dataAttributes"] does not exist, then set it to allowCommentsPIsAndDataAttributes.
To canonicalize a sanitizer list list:
Let newList be « ».
For each item in list, append the result of canonicalizing item to newList.
Return newList.
To canonicalize a processing instruction list list:
Let newList be « ».
For each item in list, append the result of canonicalizing item to newList.
Return newList.
To canonicalize a processing instruction given a SanitizerPI
pi:
To canonicalize a sanitizer name given a DOMString or dictionary name, and a default namespace
defaultNamespace (default null):
To canonicalize a sanitizer element given a SanitizerElement
element:
Return the result of canonicalizing element with the HTML namespace as the default namespace.
To canonicalize a sanitizer element list list:
Let newList be « ».
For each item in list, append the result of canonicalizing item to newList.
Return newList.
To find the canonicalized intersection of lists A and B:
Let setA be « ».
Let setB be « ».
For each entry of A, append the result of canonicalizing entry to setA.
For each entry of B, append the result of canonicalizing entry to setB.
Return the intersection of setA and setB.
The get() method
steps are:
Outside of the get() method, the order of
the Sanitizer's elements and attributes is unobservable. By explicitly sorting the
result of this method, we give implementations the opportunity to optimize by, for example, using
unordered sets internally.
Let config be this's configuration.
Assert: config is valid.
If config["elements"] exists:
For each element of config["elements"]:
If element["attributes"] exists, then set element["attributes"] to the
result of sorting element["attributes"], with
compare sanitizer items.
If element["removeAttributes"]
exists, then set element["removeAttributes"]
to the result of sorting element["removeAttributes"],
with compare sanitizer items.
Set config["elements"] to
the result of sorting config["elements"], with compare sanitizer
items.
Otherwise:
Set config["removeElements"] to the result of sorting config["removeElements"], with compare
sanitizer items.
If config["replaceWithChildrenElements"]
exists, then set config["replaceWithChildrenElements"] to
the result of sorting config["replaceWithChildrenElements"],
with compare sanitizer items.
If config["processingInstructions"] exists, then set config["processingInstructions"] to the result
of sorting config["processingInstructions"], with
piA["target"] being
code unit less than piB["target"].
Otherwise:
Set config["removeProcessingInstructions"]
to the result of sorting config["removeProcessingInstructions"],
with piA["target"]
being code unit less than piB["target"].
If config["attributes"]
exists, then set config["attributes"] to the result of sorting config["attributes"] given compare sanitizer
items.
Otherwise:
Set config["removeAttributes"] to the result of sorting config["removeAttributes"] given compare
sanitizer items.
Return config.
The allowElement(element) method steps
are:
Let configuration be this's configuration.
Assert: configuration is valid.
Set element to the result of canonicalizing element.
If configuration["elements"]
exists:
Let modified be the result of removing
element from configuration["replaceWithChildrenElements"].
If configuration["attributes"] exists:
If element["attributes"] exists:
Set element["attributes"] to the
result of creating a set from element["attributes"].
Set element["attributes"] to the
difference of element["attributes"] and
configuration["attributes"].
If configuration["dataAttributes"] is true, then remove all items item from element["attributes"] where
item is a custom data attribute.
If element["removeAttributes"]
exists:
Set element["removeAttributes"]
to the result of creating a set from
element["removeAttributes"].
Set element["removeAttributes"]
to the intersection of
element["removeAttributes"]
and configuration["attributes"].
Otherwise:
If element["attributes"] exists:
Set element["attributes"] to the
result of creating a set from element["attributes"].
Set element["attributes"] to the
difference of element["attributes"] and
element["removeAttributes"]
with default « ».
Remove element["removeAttributes"].
Set element["attributes"] to the
difference of element["attributes"] and
configuration["removeAttributes"].
If element["removeAttributes"]
exists:
Set element["removeAttributes"]
to the result of creating a set from
element["removeAttributes"].
Set element["removeAttributes"]
to the difference of element["removeAttributes"]
and configuration["removeAttributes"].
If configuration["elements"]
does not contain element:
Append element to
configuration["elements"].
Return true.
Let currentElement be the item in configuration["elements"] whose name member is element's name member and whose namespace member is
element's namespace
member.
If element is equal to currentElement, then return modified.
Remove element from
configuration["elements"].
Append element to
configuration["elements"].
Return true.
Otherwise:
If element["attributes"] exists or element["removeAttributes"]
with default « » is not empty, then return
false.
Let modified be the result of removing
element from configuration["replaceWithChildrenElements"].
If configuration["removeElements"] does not contain element, then return modified.
Remove element from
configuration["removeElements"].
Return true.
The removeElement(element) method steps
are to return the result of removing
element from this's configuration.
The replaceElementWithChildren(element)
method steps are:
Let configuration be this's configuration.
Assert: configuration is valid.
Set element to the result of canonicalizing element.
If the built-in non-replaceable elements list contains element, then return false.
Let modified be the result of removing
element from configuration["elements"].
If removing element from
configuration["removeElements"] is true, then set
modified to true.
If configuration["replaceWithChildrenElements"]
does not contain element:
Append element to
configuration["replaceWithChildrenElements"].
Return true.
Return modified.
The allowAttribute(attribute) method
steps are:
Let configuration be this's configuration.
Assert: configuration is valid.
Set attribute to the result of canonicalizing attribute.
If configuration["attributes"] exists:
If configuration["dataAttributes"] is true and
attribute is a custom data attribute, then return false.
If configuration["attributes"] contains attribute, then return false.
If configuration["elements"]
exists:
For each element in
configuration["elements"]:
If element["attributes"] with default « » contains attribute, then remove attribute from element["attributes"].
Append attribute to
configuration["attributes"].
Return true.
Otherwise:
The removeAttribute(attribute) method
steps are to return the result of removing attribute from this's
configuration.
The setComments(allow) method steps
are:
Let configuration be this's configuration.
Assert: configuration is valid.
If configuration["comments"]
exists and is equal to allow, then return
false.
Set configuration["comments"] to allow.
Return true.
The setDataAttributes(allow) method
steps are:
Let configuration be this's configuration.
Assert: configuration is valid.
If configuration["attributes"] does not exist, then return false.
If configuration["dataAttributes"] exists and is equal to allow, then return false.
If allow is true:
If configuration["elements"]
exists:
For each element of
configuration["elements"]:
If element["attributes"] exists, then remove all items
item from element["attributes"] where
item is a custom data attribute.
Remove all items item from
configuration["attributes"]
where item is a custom data attribute.
Set configuration["dataAttributes"] to allow.
Return true.
The allowProcessingInstruction(pi)
method steps are:
Let configuration be this's configuration.
Assert: configuration is valid.
Set pi to the result of canonicalizing pi.
If configuration["processingInstructions"] exists:
Otherwise:
The removeProcessingInstruction(pi)
method steps are:
Let configuration be this's configuration.
Assert: configuration is valid.
Set pi to the result of canonicalizing pi.
If configuration["processingInstructions"] exists:
Otherwise:
The removeUnsafe() method steps are to return the
result of removing unsafe from this's
configuration.
SanitizerElementNamespace, SanitizerAttributeNamespace,
SanitizerElementNamespaceWithAttributes, and
SanitizerProcessingInstruction dictionaries are considered equal when all of their
members are equal.
Equality should be defined in the infra spec instead. See issue #664.
Configurations can and ought to be modified by developers to suit their purposes. Options are
to write a new SanitizerConfig dictionary from scratch, to modify an existing
Sanitizer's configuration by using the modifier methods, or to get() an existing Sanitizer's
configuration as a dictionary and modify the dictionary and then create a new
Sanitizer with it.
An empty configuration allows everything (when called with the "unsafe" methods like setHTMLUnsafe()). A configuration "default" contains a
built-in safe default configuration. Note that "safe" and "unsafe" sanitizer methods
have different defaults.
Not all configuration dictionaries are valid. A valid configuration avoids redundancy (like specifying the same element to be allowed twice) and contradictions (like specifying an element to be both removed and allowed.)
Several conditions need to hold for a configuration to be valid:
Mixing global allow- and remove-lists:
elements or removeElements can exist, but not both. If
both are missing, this is equivalent to removeElements being an empty list.
attributes or removeAttributes can exist, but not both.
If both are missing, this is equivalent to removeAttributes being an empty
list.
dataAttributes is conceptually
an extension of the attributes allow-list.
The dataAttributes member is only
allowed when an attributes list is
used.
Duplicate entries between different global lists:
There are no duplicate entries (i.e., no same elements) between elements, removeElements, or replaceWithChildrenElements.
There are no duplicate entries (i.e., no same attributes) between attributes or removeAttributes.
Mixing local allow- and remove-lists on the same element:
When an attributes list exists,
both, either or none of the attributes and removeAttributes
lists are allowed on the same element.
When a removeAttributes list
exists, either or none of the attributes and removeAttributes
lists are allowed on the same element, but not both.
Duplicate entries on the same element:
There are no duplicate entries between attributes and removeAttributes
on the same element.
No element from the built-in non-replaceable elements list appears in replaceWithChildrenElements,
since replacing these elements with their children could lead to re-parsing issues or invalid
node trees.
The elements element allow-list can also
specify allowing or removing attributes for a given element. This is meant to mirror this
standard's structure, which knows both global attributes as well as local attributes
that apply to a specific element. Global and local attributes can be mixed, but note that
ambiguous configurations where a particular attribute would be allowed by one list and forbidden
by another, are generally invalid.
global attributes | global removeAttributes | |
|---|---|---|
local attributes | An attribute is allowed if it matches either list. No duplicates are allowed. | An attribute is only allowed if it's in the local allow list. No duplicate entries between global remove and local allow lists are allowed. Note that the global remove list has no function for this particular element, but can apply to other elements that do not have a local allow list. |
local removeAttributes | An attribute is allowed if it's in the global allow-list, but not in the local remove-list. Local remove has to be a subset of the global allow lists. | An attribute is allowed if it is in neither list. No duplicate entries between global remove and local remove lists are allowed. |
Please note the asymmetry where mostly no duplicates between global and per-element lists are permitted, but in the case of a global allow-list and a per-element remove-list the latter has to be a subset of the former. An excerpt of the table above, only focusing on duplicates, is as follows:
global attributes | global removeAttributes | |
|---|---|---|
local attributes | No duplicates are allowed. | No duplicates are allowed. |
local removeAttributes | Local remove has to be a subset of the global allow lists. | No duplicates are allowed. |
The dataAttributes setting allows
custom data attributes. The rules above easily extends
to custom data attributes if one considers dataAttributes to be an allow-list:
global attributes and dataAttributes set | |
|---|---|
local attributes | All custom data attributes are allowed. No custom data attributes can be listed in any allow-list, as that would mean a duplicate entry. |
local removeAttributes | A custom data attribute is allowed, unless it's listed in the local remove-list. No custom data attribute can be listed in the global allow-list, as that would mean a duplicate entry. |
Putting these rules in words:
Duplicates and interactions between global and local lists:
If a global attributes allow list
exists, then all element's local lists:
If a local attributes allow list
exists, there can be no duplicate entries between these lists.
If a local removeAttributes
remove list exists, then all its entries also need to be listed in the global attributes allow list.
If dataAttributes is true,
then no custom data attributes can be listed in
any of the allow-lists.
If a global removeAttributes
remove list exists:
If a local attributes allow list
exists, there can be no duplicate entries between these lists.
If a local removeAttributes
remove list exists, there can be no duplicate entries between these lists.
Not both a local attributes allow list
and local removeAttributes
remove list exists.
dataAttributes has to be
false.
The Sanitizer API is intended to prevent DOM-based cross-site scripting by traversing supplied
HTML content and removing elements and attributes according to a configuration. By design, the
setHTML() and parseHTML() methods remove script-capable markup regardless of the
configuration supplied; if any configuration could preserve such markup through these methods,
that would be a bug.
However, there are security issues that the Sanitizer API cannot prevent. The following sections describe them.
The Sanitizer API operates solely in the DOM and adds a capability to traverse and filter an
existing DocumentFragment. The Sanitizer API does not address server-side reflected
or stored XSS.
DOM clobbering describes an attack in which malicious HTML confuses an application by using
id or name attributes such that DOM
properties, such as the children property of an HTML
element, are shadowed by malicious content.
The Sanitizer API does not protect against DOM clobbering attacks by default, but can be
configured to remove id and name
attributes.
Script gadgets are a technique in which an attacker uses existing application code from popular JavaScript libraries to cause their own code to execute. This is often done by injecting innocent-looking code or seemingly inert DOM nodes that are only parsed and interpreted by a framework which then performs the execution of JavaScript based on that input.
The Sanitizer API cannot prevent these attacks. Instead, it relies on authors to explicitly
allow unknown elements in general, and additionally to explicitly allow attributes, elements, and
markup commonly used for templating and framework-specific code, such as data-* and slot attributes and
elements like slot and template. These restrictions are not exhaustive
and authors are encouraged to examine their third party libraries for this behavior.
Mutation XSS or mXSS describes an attack that exploits cases where the parsed DOM structure is not the same after serializing and parsing again, to bypass sanitization that happens before serialization. An example for carrying out such an attack is by relying on the change of parsing behavior for foreign content or mis-nested tags.
The Sanitizer API offers only functions that turn a string into a node tree. The context is supplied implicitly by all sanitizer functions: setHTML() uses the current element; Document.parseHTML() creates a new document. Therefore Sanitizer API is not directly affected by mutation XSS.
If a developer were to retrieve a sanitized node tree as a string, e.g. via innerHTML, and to then parse it again then mutation XSS can
occur. This practice is strongly discouraged. If processing or passing of HTML as a string is
necessary after all, then any string is to be considered untrusted and re-sanitized when inserted
into the DOM. In other words, a sanitized and then serialized HTML tree can no longer be
considered sanitized. A more complete treatment of mXSS can be found in [MXSS].