Skip to content

Fix exponential DOM issue in unwrap - #10

Merged
mat-sz merged 1 commit into
mat-sz:mainfrom
bfontaine:fix/unwrap
Jul 8, 2026
Merged

Fix exponential DOM issue in unwrap#10
mat-sz merged 1 commit into
mat-sz:mainfrom
bfontaine:fix/unwrap

Conversation

@bfontaine

Copy link
Copy Markdown
Contributor

Hi Mat,
This is the PR for the fix. I copy the explanation below (also in the commit message) for other readers, but it鈥檚 the same explanation that I sent you via email.
I didn鈥檛 include unit tests as you said you would write them; tell me if you want some.


This fixes an issue in the current implementation where if sanitize is called on an HTML with deep nested unallowed elements it creates an exponential number of new elements and can eventually exhaust the available memory.

For example, if you have this HTML:

<x><y><z>blabla</z></y></x>

The code first hits <x> and inserts its .innerHTML after it:

<x><y><z>blabla</z></y></x>
<y><z>blabla</z></y>

Then it hits the inner <y>, and same thing:

<x><y><z>blabla</z></y>
  <z>blabla</z></x>
<y><z>blabla</z></y>

Then the inner <z>:

<x><y><z>blabla</z>
      blabla</y>
  <z>blabla</z></x>
<y><z>blabla</z></y>

Then the first <z>鈥檚 copy, etc.
At the end, there are 7 nodes in the document (2^3-1). If you raise the depth from 3 to 20, you get 2^20-1=1M nodes.

Note that there is also a performance issue as .innerHTML serializes the whole DOM and then insertAdjacentHTML unserializes it.

This PR fixes both the exponential issue and the serialization/unserialization.

This fixes an issue in the current implementation where if `sanitize` is
called on an HTML with deep nested unallowed elements it creates an
exponential number of new elements and can eventually exhaust the
available memory.

For example, if you have this HTML:

    <x><y><z>blabla</z></y></x>

The code first hits `<x>` and inserts its `.innerHTML` after it:

    <x><y><z>blabla</z></y></x>
    <y><z>blabla</z></y>

Then it hits the inner `<y>`, and same thing:

    <x><y><z>blabla</z></y>
      <z>blabla</z></x>
    <y><z>blabla</z></y>

Then the inner `<z>`:

    <x><y><z>blabla</z>
          blabla</y>
      <z>blabla</z></x>
    <y><z>blabla</z></y>

Then the first `<z>`鈥檚 copy, etc.
At the end, there are 7 nodes in the document (2^3-1).
If you raise the depth from 3 to 20, you get 2^20-1=1M nodes.

Note that there is also a performance issue as `.innerHTML` serializes
the whole DOM and then `insertAdjacentHTML` unserializes it.

This commit fixes both the exponential issue and the
serialization/unserialization.
@mat-sz

mat-sz commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Thank you for the research. I'll release this in the next patch version.

@mat-sz
mat-sz merged commit 9d88dce into mat-sz:main Jul 8, 2026
1 check passed
@bfontaine
bfontaine deleted the fix/unwrap branch July 8, 2026 19:21
@mat-sz

mat-sz commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Available in version v1.0.8. Thank you again.

bfontaine added a commit to bfontaine/chatwoot that referenced this pull request Jul 9, 2026
This release includes a [patch][1] that fixes an [issue][2] affecting
Chatwoot: in some cases, if you receive a malformed email with
deeply-nested tags considered unvalid by `lettersanitizer`, just
selecting the email in your inbox causes the browser tab or even the
whole computer to freeze, due to RAM exhaustion.

[1]: mat-sz/lettersanitizer#10
[2]: GHSA-hhw2-373g-hx77

Also, bump vue-letter from 0.2.1 to 0.2.2, which bumped its own
lettersanitizer dependency to 1.0.8.
bfontaine added a commit to bfontaine/chatwoot that referenced this pull request Jul 9, 2026
This release includes a [patch][1] that fixes an [issue][2] affecting
Chatwoot: in some cases, if you receive a malformed email with
deeply-nested tags considered unvalid by `lettersanitizer`, just
selecting the email in your inbox causes the browser tab or even the
whole computer to freeze, due to RAM exhaustion.

[1]: mat-sz/lettersanitizer#10
[2]: GHSA-hhw2-373g-hx77

Also, bump vue-letter from 0.2.1 to 0.2.2, which bumped its own
lettersanitizer dependency to 1.0.8.
bfontaine added a commit to bfontaine/chatwoot that referenced this pull request Jul 9, 2026
This release includes a [patch][1] that fixes an [issue][2] affecting
Chatwoot: in some cases, if you receive a malformed email with
deeply-nested tags considered unvalid by `lettersanitizer`, just
selecting the email in your inbox causes the browser tab or even the
whole computer to freeze, due to RAM exhaustion.

[1]: mat-sz/lettersanitizer#10
[2]: GHSA-hhw2-373g-hx77

Also, bump vue-letter from 0.2.1 to 0.2.2, which bumped its own
lettersanitizer dependency to 1.0.8.
bfontaine added a commit to bfontaine/chatwoot that referenced this pull request Jul 9, 2026
This release includes a [patch][1] that fixes an [issue][2] affecting
Chatwoot: in some cases, if you receive a malformed email with
deeply-nested tags considered unvalid by `lettersanitizer`, just
selecting the email in your inbox causes the browser tab or even the
whole computer to freeze, due to RAM exhaustion.

[1]: mat-sz/lettersanitizer#10
[2]: GHSA-hhw2-373g-hx77

Also, bump vue-letter from 0.2.1 to 0.2.2, which bumped its own
lettersanitizer dependency to 1.0.8.
bfontaine added a commit to bfontaine/chatwoot that referenced this pull request Jul 13, 2026
This release includes a [patch][1] that fixes an [issue][2] affecting
Chatwoot: in some cases, if you receive a malformed email with
deeply-nested tags considered unvalid by `lettersanitizer`, just
selecting the email in your inbox causes the browser tab or even the
whole computer to freeze, due to RAM exhaustion.

[1]: mat-sz/lettersanitizer#10
[2]: GHSA-hhw2-373g-hx77

Also, bump vue-letter from 0.2.1 to 0.2.2, which bumped its own
lettersanitizer dependency to 1.0.8.
bfontaine added a commit to bfontaine/chatwoot that referenced this pull request Jul 14, 2026
This release includes a [patch][1] that fixes an [issue][2] affecting
Chatwoot: in some cases, if you receive a malformed email with
deeply-nested tags considered unvalid by `lettersanitizer`, just
selecting the email in your inbox causes the browser tab or even the
whole computer to freeze, due to RAM exhaustion.

[1]: mat-sz/lettersanitizer#10
[2]: GHSA-hhw2-373g-hx77

Also, bump vue-letter from 0.2.1 to 0.2.2, which bumped its own
lettersanitizer dependency to 1.0.8.
bfontaine added a commit to bfontaine/chatwoot that referenced this pull request Jul 16, 2026
This release includes a [patch][1] that fixes an [issue][2] affecting
Chatwoot: in some cases, if you receive a malformed email with
deeply-nested tags considered unvalid by `lettersanitizer`, just
selecting the email in your inbox causes the browser tab or even the
whole computer to freeze, due to RAM exhaustion.

[1]: mat-sz/lettersanitizer#10
[2]: GHSA-hhw2-373g-hx77

Also, bump vue-letter from 0.2.1 to 0.2.2, which bumped its own
lettersanitizer dependency to 1.0.8.
sojan-official pushed a commit to chatwoot/chatwoot that referenced this pull request Aug 12, 2026
# Pull Request Template

## Description

This PR bumps lettersanitizer to 1.0.8, because that release includes a
[patch][1] that fixes an [issue][2] affecting Chatwoot: in some cases,
if you receive a malformed email with deeply-nested tags considered
unvalid by `lettersanitizer`, just selecting the email in your inbox
causes the browser tab or even the whole computer to freeze, due to RAM
exhaustion.

[1]: mat-sz/lettersanitizer#10
[2]:
GHSA-hhw2-373g-hx77

Edit: also bump `vue-letter` to 0.2.2 to update its own
`lettersanitizer` dependency
(mat-sz/vue-letter#3), per
#14959 (comment).

## Type of change

Please delete options that are not relevant.

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality not to work as expected)
- [ ] This change requires a documentation update

## How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration.


## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] ~~I have commented on my code, particularly in hard-to-understand
areas~~
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [x] Any dependent changes have been merged and published in downstream
modules
gabrieljablonski pushed a commit to fazer-ai/chatwoot that referenced this pull request Aug 30, 2026
# Pull Request Template

## Description

This PR bumps lettersanitizer to 1.0.8, because that release includes a
[patch][1] that fixes an [issue][2] affecting Chatwoot: in some cases,
if you receive a malformed email with deeply-nested tags considered
unvalid by `lettersanitizer`, just selecting the email in your inbox
causes the browser tab or even the whole computer to freeze, due to RAM
exhaustion.

[1]: mat-sz/lettersanitizer#10
[2]:
GHSA-hhw2-373g-hx77

Edit: also bump `vue-letter` to 0.2.2 to update its own
`lettersanitizer` dependency
(mat-sz/vue-letter#3), per
chatwoot#14959 (comment).

## Type of change

Please delete options that are not relevant.

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality not to work as expected)
- [ ] This change requires a documentation update

## How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration.


## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] ~~I have commented on my code, particularly in hard-to-understand
areas~~
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [x] Any dependent changes have been merged and published in downstream
modules
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants