From 78fdfd9e3a2fa08a106823d1a3e5684b36e49abd Mon Sep 17 00:00:00 2001 From: Noam Rosenthal Date: Wed, 1 Jul 2026 15:28:25 +0100 Subject: [PATCH 01/11] Sanitize while parsing --- source | 557 +++++++++++++++++++++++++++------------------------------ 1 file changed, 268 insertions(+), 289 deletions(-) diff --git a/source b/source index 6df0e4dbdb9..3b41e8a132f 100644 --- a/source +++ b/source @@ -125540,8 +125540,10 @@ enum DOMParserSupportedType {
-

To parse HTML from a string, given a Document document and a - string html:

+

To parse HTML from a string, given a Document document, a + string html, an optional SanitizerConfig or null + configuration (default null), and an optional boolean safe (default + false):

  1. Set document's type to "DOMParserSupportedType { data-x="concept-document-allow-declarative-shadow-roots">allow declarative shadow roots, associated with document.

  2. +
  3. If configuration is not null, then set parser's parser + sanitizer configuration to configuration and set parser's + remove javascript navigation URLs to safe.

  4. +
  5. Place html into the input stream for parser. The encoding confidence is irrelevant.

  6. @@ -125574,46 +125580,45 @@ enum DOMParserSupportedType {
    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.

    + 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 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.

    + data-x="dom-SetHTMLUnsafeOptions-sanitizer">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.

    + data-x="dom-SetHTMLUnsafeOptions-sanitizer">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.

    + 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)
    @@ -125625,8 +125630,8 @@ enum DOMParserSupportedType { 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.

    + data-x="dom-ParseHTMLUnsafeOptions-sanitizer">sanitizer" member, it is used to sanitize + the resulting DOM.

    @@ -125725,8 +125730,13 @@ enum DOMParserSupportedType {
  7. Let sanitizer be the result of calling get a sanitizer instance from options with options and true.

  8. -
  9. Call sanitize on document with sanitizer and - true.

  10. +
  11. Let configuration be sanitizer's + configuration.

  12. + +
  13. Remove unsafe from configuration.

  14. + +
  15. Parse HTML from a string given document, html, + configuration, and true.

  16. Return document.

@@ -125758,14 +125768,14 @@ enum DOMParserSupportedType { data-x="concept-document-allow-declarative-shadow-roots">allow declarative shadow roots to true.

-
  • Parse HTML from a string given document and - compliantHTML.

  • -
  • Let sanitizer be the result of calling get a sanitizer instance from options with options and false.

  • -
  • Call sanitize on document with sanitizer and - false.

  • +
  • Let configuration be sanitizer's + configuration.

  • + +
  • Parse HTML from a string given document, compliantHTML, + configuration, and false.

  • Return document.

  • @@ -127643,6 +127653,12 @@ dictionary SanitizerConfig {
  • Let sanitizer be the result of calling getting a sanitizer from options given safe.

  • +
  • Let configuration be sanitizer's + configuration.

  • + +
  • If safe is true, then remove unsafe from + configuration.

  • +
  • Let scriptingMode be Inert.

  • @@ -127658,16 +127674,14 @@ dictionary SanitizerConfig {
  • -

    Let fragment be the result of invoking the HTML fragment parsing - algorithm given target, html, true, and - scriptingMode.

    +

    Let fragment be the result of parsing a fragment given target, html, true, + scriptingMode, configuration, and safe.

    Scripts in fragment will only execute once inserted into target.

  • -
  • Sanitize fragment given sanitizer and - safe.

  • Replace all with fragment within target.

  • @@ -127722,276 +127736,191 @@ dictionary SanitizerConfig {
    -

    To sanitize a Node node with a Sanitizer - sanitizer and a boolean safe:

    -
      -
    1. Let configuration be sanitizer's - configuration.

    2. +

      To determine whether an attribute attribute contains a javascript: + URL:

      -
    3. Assert: configuration is valid.

    4. +
        +
      1. Let url be the result of running the basic URL parser on + attribute's value.

      2. -
      3. If safe is true, then remove unsafe from - configuration.

      4. +
      5. If url is failure, then return false.

      6. -
      7. Run the inner sanitize steps given node, configuration, - and safe.

      8. +
      9. Return true if url's scheme is "javascript", and false otherwise.

    -

    To perform the inner sanitize steps given a Node node, a - SanitizerConfig configuration, and a boolean - handleJavascriptNavigationUrls:

    +

    To check if a sanitizer config allows comments given a SanitizerConfig + configuration: Return true if configuration["comments"] is true; otherwise false.

    +
    + +
    +

    To check if a sanitizer config allows processing instruction target given a + string piTarget and a SanitizerConfig + configuration:

    1. -

      For each child of node's children:

      +

      If configuration["processingInstructions"] exists, then:

        -
      1. Assert: child is a Text, Comment, - Element, ProcessingInstruction, or DocumentType - node.

      2. +
      3. If configuration["processingInstructions"] does not + contain piTarget, then return false.

      4. +
      +
    2. -
    3. If child is a DocumentType or Text node, then - continue.

    4. +
    5. Otherwise, if configuration["removeProcessingInstructions"] + contains piTarget, return false.

    6. -
    7. -

      If child is a Comment node:

      +
    8. Return true.

    9. +
    +
    -
      -
    1. If configuration["comments"] is not true, then remove child.

    2. +
      +

      To sanitize an Element element given a + SanitizerConfig configuration and a boolean + removeJavascriptNavigationUrls:

      +
        +
      1. Let elementName be a SanitizerElementNamespace with + element's local name and namespace.

      2. -
      3. Continue.

      4. -
      - +
    3. +

      If configuration["replaceWithChildrenElements"] + exists and configuration["replaceWithChildrenElements"] + contains elementName, then return "Replace with children".

      +
    4. +
    5. +

      If configuration["elements"] + exists, then:

      + +
      1. -

        If child is a ProcessingInstruction node:

        +

        If configuration["elements"] + does not contain elementName, then return + "Remove".

        +
      2. +
      +
    6. -
        -
      1. Let piTarget be child's target.

      2. +
      3. +

        Otherwise, if configuration["removeElements"] contains elementName, return "Remove".

        +
      4. -
      5. -

        If configuration["processingInstructions"] exists:

        +
      6. +

        For each attribute of element's + attribute list:

        -
          -
        1. If configuration["processingInstructions"] does - not contain piTarget, then remove child.

        2. -
        -
      7. +
          +
        1. Let attrName be a SanitizerAttributeNamespace with + attribute's local name and namespace.

        2. -
        3. -

          Otherwise:

          +
        4. Let elementWithLocalAttributes be «[ ]».

        5. -
            -
          1. If configuration["removeProcessingInstructions"] - contains piTarget, then remove child.

          2. -
          - -
        +
      8. If configuration["elements"] exists + and configuration["elements"] + contains elementName, then set + elementWithLocalAttributes to configuration["elements"][elementName].

      9. + +
      10. +

        If elementWithLocalAttributes["removeAttributes"] + exists and elementWithLocalAttributes["removeAttributes"] + contains attrName, then remove attribute from + element's attribute list and continue.

      11. -

        Otherwise:

        +

        Otherwise, if configuration["attributes"] exists, then:

          -
        1. Let elementName be a SanitizerElementNamespace with - child's local name and namespace.

        2. - -
        3. If configuration["replaceWithChildrenElements"] - exists and configuration["replaceWithChildrenElements"] - contains elementName:

          - -
            -
          1. Assert: node is not a Document.

          2. - -
          3. Run the inner sanitize steps given child, - configuration, and handleJavascriptNavigationUrls.

          4. - -
          5. Let fragment be a new DocumentFragment whose node - document is node's node document.

          6. - -
          7. For each innerChild of - child's children, append innerChild to - fragment.

          8. - -
          9. Replace child with - fragment within node. Assert that this did not - throw.

          10. - -
          11. Continue.

          12. -
          -
        4. -
        5. If configuration["elements"] exists:

          - -
            -
          1. If configuration["elements"] does not contain elementName, then remove child and - continue.

          2. -
          -
        6. - -
        7. -

          Otherwise:

          - -
            -
          1. If configuration["removeElements"] contains elementName, then remove child and - continue.

          2. -
          + data-x="dom-SanitizerConfig-attributes">attributes"] does not contain attrName and + elementWithLocalAttributes["attributes"] with default « » does not contain attrName, and if "data-" is not a + code unit prefix of attribute's local name or attribute's namespace is not null or + configuration["dataAttributes"] is not true, then remove attribute from + element's attribute list and continue.

        8. +
        +
      12. -
      13. If elementName["name"] is "template" and - elementName["namespace"] is the HTML - namespace, then run the inner sanitize steps given child's - template contents, configuration, and - handleJavascriptNavigationUrls.

      14. - -
      15. If child is a shadow host, then run the inner sanitize - steps given child's shadow root, configuration, and - handleJavascriptNavigationUrls.

      16. - -
      17. Let elementWithLocalAttributes be «[ ]».

      18. - -
      19. If configuration["elements"] exists and configuration["elements"] contains elementName, then set - elementWithLocalAttributes to configuration["elements"][elementName].

      20. - -
      21. -

        For each attribute in child's - attribute list:

        - -
          -
        1. Let attrName be a SanitizerAttributeNamespace with - attribute's local name and - namespace.

        2. - -
        3. If elementWithLocalAttributes["removeAttributes"] - exists and elementWithLocalAttributes["removeAttributes"] - contains attrName, then remove attribute.

        4. - -
        5. -

          Otherwise, if configuration["attributes"] exists:

          - -
            -
          1. If configuration["attributes"] does not contain attrName and - elementWithLocalAttributes["attributes"] with default « » does not contain attrName, and if "data-" is - not a code unit prefix of attribute's local name or attribute's namespace is not null or - configuration["dataAttributes"] is not true, then - remove - attribute.

          2. -
          -
        6. +
        7. +

          Otherwise:

          -
        8. -

          Otherwise:

          +
            +
          1. If elementWithLocalAttributes["attributes"] exists and elementWithLocalAttributes["attributes"] does not + contain attrName, then remove attribute from + element's attribute list and continue.

          2. + +
          3. Otherwise, if configuration["removeAttributes"] contains attrName, remove attribute from + element's attribute list and continue.

          4. +
          +
        9. -
            -
          1. If elementWithLocalAttributes["attributes"] exists and elementWithLocalAttributes["attributes"] does - not contain attrName, then remove attribute.

          2. - -
          3. Otherwise, if configuration["removeAttributes"] contains attrName, then remove attribute.

          4. -
          - +
        10. If removeJavascriptNavigationUrls is false, then + continue.

        11. -
        12. -

          If handleJavascriptNavigationUrls is true:

          +
        13. If the pair (elementName, attrName) matches an entry in the + built-in navigating URL attributes list, and if attribute + contains a javascript: URL, then remove attribute from + element's attribute list.

        14. -
            -
          1. If the pair (elementName, attrName) matches an entry in the - built-in navigating URL attributes list, and if attribute - contains a javascript: URL, then remove attribute.

          2. - -
          3. If child's namespace is - the MathML Namespace, attribute's local name is "href", - attribute's namespace is - null or the XLink namespace, and attribute contains a - javascript: URL, then remove attribute.

          4. - -
          5. If the built-in animating URL attributes list contains the pair (elementName, attrName), and - attribute's value is "href" or "xlink:href", then remove attribute.

          6. -
          - -
        -
      22. +
      23. If element's namespace is the + MathML Namespace, attribute's local name is "href", + attribute's namespace is null or + the XLink namespace, and attribute contains a + javascript: URL, then remove attribute from + element's attribute list.

      24. -
      25. Run the inner sanitize steps given child, - configuration, and handleJavascriptNavigationUrls.

      26. -
      - +
    7. If the built-in animating URL attributes list contains the pair (elementName, attrName), and + attribute's value is "href" or "xlink:href", then remove attribute from + element's attribute list.

    - - - -
    -

    To determine whether an attribute attribute contains a javascript: - URL:

    -
      -
    1. Let url be the result of running the basic URL parser on - attribute's value.

    2. - -
    3. If url is failure, then return false.

    4. - -
    5. Return true if url's scheme is "javascript", and false otherwise.

    6. +
    7. Return "Keep".

    @@ -141464,9 +141393,6 @@ dictionary StorageEventInit : EventInit {
    Other parsing state flags
    -

    The root insertion target, which is null or a DocumentFragment - (initially null).

    -

    A boolean allow declarative shadow roots (initially false).

    The scripting mode, which is a parser scripting mode.

    @@ -141499,6 +141425,14 @@ dictionary StorageEventInit : EventInit {

    The frameset-ok flag is set to "ok" when the parser is created. It is set to "not ok" after certain tokens are seen.

    +

    A SanitizerConfig-or-null parser sanitizer configuration, initially + null.

    + +

    A boolean remove javascript navigation URLs, initially false.

    + +

    The insertion target redirection map is an ordered map, initially + empty.

    +

    Tokenization

    @@ -144308,7 +144242,6 @@ dictionary StorageEventInit : EventInit { recognized that practical concerns will likely force user agents to impose nesting depth constraints.

    -
    Creating and inserting nodes

    While the parser is processing a token, it can enable or disable exists, then set adjustedInsertionLocation to + that.

    + +
  • Return adjustedInsertionLocation.

  • @@ -144552,7 +144487,34 @@ dictionary StorageEventInit : EventInit { element:

      -
    1. Let insertionLocation be the adjusted insertion location.

    2. +
    3. Let the insertionLocation be the adjusted insertion + location.

    4. + +
    5. +

      If the parser's parser sanitizer configuration is not null, then:

      + +
        +
      1. Let action be the result of sanitizing + element given the parser's parser sanitizer configuration and the + parser's remove javascript navigation URLs.

      2. + +
      3. +

        Switch on action:

        + +
        +
        "Replace with children"
        +
        Set the parser's insertion target redirection map[element] to + insertionLocation, and abort these steps.
        + +
        "Remove"
        +
        Abort these steps.
        + +
        "Keep"
        +
        Do nothing.
        +
        +
      4. +
      +
    6. If it is not possible to insert element at insertionLocation, abort these steps.

    7. @@ -144726,8 +144688,11 @@ dictionary StorageEventInit : EventInit {
    8. Let insertionLocation be the adjusted insertion location.

    9. +
    10. If insertionLocation is null, then return.

    11. +
    12. -

      If insertionLocation is in a Document node, then return.

      +

      If insertionLocation is in a Document node, + then return.

      The DOM will not let Document nodes have Text node children, so they are dropped on the floor.

      @@ -144796,17 +144761,23 @@ document.body.appendChild(text); the user agent must run the following steps:

        +
      1. If the parser's parser sanitizer configuration is non-null and does not + allow comments, then abort these + steps.

      2. +
      3. Let data be the data given in the comment token being processed.

      4. Set insertionLocation to the adjusted insertion location given insertionLocation.

      5. -
      6. Create a Comment node whose data attribute is set to - data and whose node document is the same as that of the node in which the - insertionLocation finds itself.

        +
      7. If insertionLocation is null, then abort these steps.

      8. + +
      9. Let comment be a Comment node whose data + attribute is set to data and whose node document is the same as that of + the node in which the insertionLocation finds itself.

      10. -
      11. Insert the newly created node at insertionLocation.

      12. +
      13. Insert comment at insertionLocation.

      @@ -144819,18 +144790,22 @@ document.body.appendChild(text);
    13. Let target be the target given in the processing instruction token being processed.

    14. +
    15. If the parser's parser sanitizer configuration is non-null and it does not + allow + target, then abort these steps.

    16. +
    17. Let data be the data given in the processing instruction token being processed.

    18. Set insertionLocation to the adjusted insertion location given insertionLocation.

    19. -
    20. Create a ProcessingInstruction node whose

      Let pi be a new ProcessingInstruction node whose target is target, data is data, and node document is the same as that of the node in which the insertionLocation finds itself.

      -
    21. Insert the newly created node at insertionLocation.

    22. +
    23. Insert pi at insertionLocation.

    @@ -149639,9 +149614,11 @@ console.assert(container.firstChild instanceof SuperP);

    The HTML fragment parsing algorithm, given an Element or - DocumentFragment target, a string input, an optional boolean - allowDeclarativeShadowRoots (default false), and an optional parser scripting - mode scriptingMode (default Inert), + DocumentFragment target, a string input, an + optional boolean allowDeclarativeShadowRoots (default false), an optional + parser scripting mode scriptingMode (default Inert), an optional SanitizerConfig or null + configuration (default null), and an optional boolean safe (default false), is the following steps. They return a DocumentFragment.

    Parts marked fragment case in algorithms in the HTML @@ -149677,15 +149654,16 @@ console.assert(container.firstChild instanceof SuperP); document's mode to "limited-quirks".

    -
  • Create a new HTML parser whose allow declarative shadow roots is - allowDeclarativeShadowRoots, and associate it with document.

  • +
  • Create a new HTML parser whose parser sanitizer configuration is + configuration, allow declarative shadow roots is + allowDeclarativeShadowRoots, scripting mode is + scriptingMode, and remove javascript navigation URLs + is safe, and associate it with document.

  • If contextDocument's scripting is disabled, then set scriptingMode to Disabled.

  • -
  • Set the parser's scripting mode to scriptingMode.

  • -
  • Set the state of the HTML parser's tokenization stage as follows, switching on context:

    @@ -149739,7 +149717,8 @@ console.assert(container.firstChild instanceof SuperP);
  • Let fragment be a new DocumentFragment whose node document is target's node document.

  • -
  • Set the parser's root insertion target to fragment.

  • +
  • Set the parser's insertion target redirection map[root] to + fragment, right after its last child (if exists).

  • If context is a template element, then push "in template" onto the From 3f460b9149706f379cf8ec4497d86603fc172111 Mon Sep 17 00:00:00 2001 From: Noam Rosenthal Date: Thu, 9 Jul 2026 13:16:43 +0100 Subject: [PATCH 02/11] Editorial: style and line length improvements in Sanitizer algorithms --- source | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/source b/source index 3b41e8a132f..26d4ef714b0 100644 --- a/source +++ b/source @@ -127840,18 +127840,19 @@ dictionary SanitizerConfig {

  • If elementWithLocalAttributes["removeAttributes"] - exists and elementWithLocalAttributes["removeAttributes"] - contains attrName, then remove attribute from + data-x="dom-SanitizerElementNamespaceWithAttributes-removeAttributes" + >removeAttributes"] exists and + elementWithLocalAttributes["removeAttributes"] contains attrName, + then remove attribute from element's attribute list and continue.

  • Otherwise, if configuration["attributes"] exists, then:

    + exists">exists:

    1. From 95340588af2f48f91c40fe8c09da26bfac25fd3e Mon Sep 17 00:00:00 2001 From: Noam Rosenthal Date: Thu, 9 Jul 2026 13:24:27 +0100 Subject: [PATCH 03/11] Editorial: restore sanitize/sanitized cross-references in domintro blocks --- source | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/source b/source index 26d4ef714b0..de35503bfd7 100644 --- a/source +++ b/source @@ -125580,45 +125580,46 @@ enum DOMParserSupportedType {
      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.

      + 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 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.

      + data-x="dom-SetHTMLUnsafeOptions-sanitizer">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.

      + data-x="dom-SetHTMLUnsafeOptions-sanitizer">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.

      + 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)
      @@ -125630,8 +125631,8 @@ enum DOMParserSupportedType { 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.

      + data-x="dom-ParseHTMLUnsafeOptions-sanitizer">sanitizer" member, it is used to + sanitize the resulting DOM.

      From 09ffc0a273b663fbd1d1c145a4a3c816b6cc162d Mon Sep 17 00:00:00 2001 From: Noam Rosenthal Date: Thu, 9 Jul 2026 13:41:05 +0100 Subject: [PATCH 04/11] Editorial: undo unnecessary line wrapping on Document node insertion check --- source | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source b/source index de35503bfd7..a704148de6a 100644 --- a/source +++ b/source @@ -144693,8 +144693,7 @@ dictionary StorageEventInit : EventInit {
    2. If insertionLocation is null, then return.

    3. -

      If insertionLocation is in a Document node, - then return.

      +

      If insertionLocation is in a Document node, then return.

      The DOM will not let Document nodes have Text node children, so they are dropped on the floor.

      From f137d80a5854a869fdb2ad28d995326a7f05b0b0 Mon Sep 17 00:00:00 2001 From: Noam Rosenthal Date: Thu, 9 Jul 2026 13:57:17 +0100 Subject: [PATCH 05/11] Create fragment in the inert document --- source | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/source b/source index a704148de6a..f8062e3e463 100644 --- a/source +++ b/source @@ -149715,8 +149715,13 @@ console.assert(container.firstChild instanceof SuperP);
    4. Set up the HTML parser's stack of open elements so that it contains just the single element root.

    5. -
    6. Let fragment be a new DocumentFragment whose node - document is target's node document.

    7. +
    8. +

      Let fragment be a new DocumentFragment whose node + document is document.

      + +

      The DocumentFragment is created as part of the inert document to + avoid creation time side effects before sanitization.

      +
    9. Set the parser's insertion target redirection map[root] to fragment, right after its last child (if exists).

    10. From 91fb4c0ef830d1c01ebb335f8b117e70cca95320 Mon Sep 17 00:00:00 2001 From: Noam Rosenthal Date: Thu, 9 Jul 2026 14:11:39 +0100 Subject: [PATCH 06/11] Editorial: remove unreachable null checks of adjusted insertion location result --- source | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/source b/source index f8062e3e463..41e7303a397 100644 --- a/source +++ b/source @@ -127654,11 +127654,11 @@ dictionary SanitizerConfig {
    11. Let sanitizer be the result of calling getting a sanitizer from options given safe.

    12. -
    13. Let configuration be sanitizer's +

    14. Let sanitizerConfig be sanitizer's configuration.

    15. If safe is true, then remove unsafe from - configuration.

    16. + sanitizerConfig.

    17. Let scriptingMode be Inert.

    18. @@ -127675,9 +127675,9 @@ dictionary SanitizerConfig {
    19. -

      Let fragment be the result of parsing a fragment given target, html, true, - scriptingMode, configuration, and safe.

      +

      Let fragment be the result of invoking the HTML fragment parsing + algorithm given target, html, true, scriptingMode, + sanitizerConfig, and safe.

      Scripts in fragment will only execute once inserted into target.

      @@ -127804,7 +127804,7 @@ dictionary SanitizerConfig {
    20. If configuration["elements"] - exists, then:

      + exists:

      1. @@ -144489,8 +144489,7 @@ dictionary StorageEventInit : EventInit { element:

          -
        1. Let the insertionLocation be the adjusted insertion - location.

        2. +
        3. Let insertionLocation be the adjusted insertion location.

        4. If the parser's parser sanitizer configuration is not null, then:

          @@ -144690,8 +144689,6 @@ dictionary StorageEventInit : EventInit {
        5. Let insertionLocation be the adjusted insertion location.

        6. -
        7. If insertionLocation is null, then return.

        8. -
        9. If insertionLocation is in a Document node, then return.

          @@ -144772,8 +144769,6 @@ document.body.appendChild(text);
        10. Set insertionLocation to the adjusted insertion location given insertionLocation.

        11. -
        12. If insertionLocation is null, then abort these steps.

        13. -
        14. Let comment be a Comment node whose data attribute is set to data and whose node document is the same as that of the node in which the insertionLocation finds itself.

        15. From 5d61b72ff453b59c73b4e6938eae0881b5878aec Mon Sep 17 00:00:00 2001 From: Noam Rosenthal Date: Thu, 9 Jul 2026 14:12:39 +0100 Subject: [PATCH 07/11] adjusted insertion location is never null --- source | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source b/source index 41e7303a397..ad18cb341fe 100644 --- a/source +++ b/source @@ -144796,12 +144796,12 @@ document.body.appendChild(text);
        16. Set insertionLocation to the adjusted insertion location given insertionLocation.

        17. -
        18. Let pi be a new ProcessingInstruction node whose

          Create a new ProcessingInstruction node whose target is target, data is data, and node document is the same as that of the node in which the insertionLocation finds itself.

          -
        19. Insert pi at insertionLocation.

        20. +
        21. Insert the newly created node at insertionLocation.

  • From 6714ff1f234183949c63ec7a976ecb099a493832 Mon Sep 17 00:00:00 2001 From: Noam Rosenthal Date: Thu, 9 Jul 2026 16:01:21 +0100 Subject: [PATCH 08/11] Preserve reference child in insertion redirection for foster parenting --- source | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/source b/source index ad18cb341fe..453ce3d4f4f 100644 --- a/source +++ b/source @@ -144474,9 +144474,28 @@ dictionary StorageEventInit : EventInit {
  • Let targetParent be the node in which adjustedInsertionLocation finds itself.

  • -
  • If the parser's insertion target redirection map[targetParent] - exists, then set adjustedInsertionLocation to - that.

  • +
  • +

    If the parser's insertion target redirection map[targetParent] + exists, then:

    + +
      +
    1. Let redirectedLocation be the parser's insertion target redirection + map[targetParent].

    2. + +
    3. Let redirectedParent be the node in which redirectedLocation + finds itself.

    4. + +
    5. +

      If adjustedInsertionLocation is immediately before a node + referenceChild, and referenceChild's parent node is + redirectedParent, then set adjustedInsertionLocation to inside + redirectedParent, immediately before referenceChild.

      +
    6. + +
    7. Otherwise, set adjustedInsertionLocation to + redirectedLocation.

    8. +
    +
  • Return adjustedInsertionLocation.

  • From 40783e5340f317b6b69c9edde8f8663308d8435e Mon Sep 17 00:00:00 2001 From: Noam Rosenthal Date: Tue, 14 Jul 2026 16:05:32 +0100 Subject: [PATCH 09/11] ref-node --- source | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/source b/source index 453ce3d4f4f..730e463bc33 100644 --- a/source +++ b/source @@ -144474,30 +144474,24 @@ dictionary StorageEventInit : EventInit {
  • Let targetParent be the node in which adjustedInsertionLocation finds itself.

  • -
  • -

    If the parser's insertion target redirection map[targetParent] - exists, then:

    +
  • If the parser's insertion target redirection map[targetParent] + does not exist, then return + adjustedInsertionLocation.

  • -
      -
    1. Let redirectedLocation be the parser's insertion target redirection - map[targetParent].

    2. +
    3. Let refChild be the node before which adjustedInsertionLocation + finds itself, if any.

    4. -
    5. Let redirectedParent be the node in which redirectedLocation - finds itself.

    6. +
    7. Let redirectedLocation be the parser's insertion target redirection + map[targetParent].

    8. -
    9. -

      If adjustedInsertionLocation is immediately before a node - referenceChild, and referenceChild's parent node is - redirectedParent, then set adjustedInsertionLocation to inside - redirectedParent, immediately before referenceChild.

      -
    10. +
    11. Let redirectedParent be the node in which redirectedLocation + finds itself.

    12. -
    13. Otherwise, set adjustedInsertionLocation to - redirectedLocation.

    14. -
    - +
  • If refChild is a node whose parent node is + redirectedParent, then return a location inside redirectedParent, + immediately before refChild.

  • -
  • Return adjustedInsertionLocation.

  • +
  • Return redirectedLocation.

  • From faff120e128a5b3c4cef604238455bfdefd2fea5 Mon Sep 17 00:00:00 2001 From: Noam Rosenthal Date: Tue, 14 Jul 2026 16:06:16 +0100 Subject: [PATCH 10/11] Restored explanatory notes for redirection map and reference node with correct formatting and indentation --- source | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/source b/source index 730e463bc33..470e8cc10f9 100644 --- a/source +++ b/source @@ -144466,30 +144466,45 @@ dictionary StorageEventInit : EventInit {
    1. Let overrideTarget be null if insertionLocation is null; - otherwise the node in which insertionLocation finds itself.

    2. + otherwise the node in which insertionLocation finds itself.

    3. Let the adjustedInsertionLocation be the appropriate place for inserting - a node given overrideTarget.

    4. + a node given overrideTarget.

    5. Let targetParent be the node in which adjustedInsertionLocation - finds itself.

    6. + finds itself.

    7. If the parser's insertion target redirection map[targetParent] - does not exist, then return - adjustedInsertionLocation.

    8. + does not exist, then return + adjustedInsertionLocation.

    9. Let refChild be the node before which adjustedInsertionLocation - finds itself, if any.

    10. + finds itself, if any.

      -
    11. Let redirectedLocation be the parser's insertion target redirection - map[targetParent].

    12. +
    13. +

      Let redirectedLocation be the parser's insertion target redirection + map[targetParent].

      + +

      The insertion target redirection map is used to insert elements to + the target DocumentFragment during the fragment parsing algorithm + steps, or for elements that are replaced with children as + part of sanitization.

      +
    14. Let redirectedParent be the node in which redirectedLocation - finds itself.

    15. + finds itself.

      -
    16. If refChild is a node whose parent node is - redirectedParent, then return a location inside redirectedParent, - immediately before refChild.

    17. +
    18. +

      If refChild is a node whose parent node is redirectedParent, then + return a location inside redirectedParent, immediately before + refChild.

      + +

      This can occur when an element is replaced with its children as + part of sanitization in the middle of foster parenting.

      +
    19. Return redirectedLocation.

    From b7dd06743bb3904858f34c60137343659c351add Mon Sep 17 00:00:00 2001 From: Noam Rosenthal Date: Wed, 15 Jul 2026 14:53:54 +0100 Subject: [PATCH 11/11] Remove redundant parse HTML --- source | 3 --- 1 file changed, 3 deletions(-) diff --git a/source b/source index 470e8cc10f9..af80f4daa17 100644 --- a/source +++ b/source @@ -125725,9 +125725,6 @@ enum DOMParserSupportedType { data-x="concept-document-allow-declarative-shadow-roots">allow declarative shadow roots to true.

    -
  • Parse HTML from a string given document and - html.

  • -
  • Let sanitizer be the result of calling get a sanitizer instance from options with options and true.