html-dom-parser icon indicating copy to clipboard operation
html-dom-parser copied to clipboard

Support Trusted Types API to prevent XSS attacks

Open ValerianClerc opened this issue 6 months ago • 5 comments

Problem

Currently, html-dom-parser unsafely assigns strings to innerHtml. Browsers now support a method for developers to assert that any innerHtml has been sanitized and is safe to assign to innerHtml, in the form of TrustedTypes. See documentation here:

Suggested Solution

I can think of 2 ways to fix this:

  1. Allow the user to pass in a TrustedHTML object instead of a string. This would mean that the caller of html-dom-parser would do the sanitization, and then pass in a safe string into html-dom-parser.
    • This strategy requires relaxing the check for typeof "string" here in the code. However, we would also need to avoid any re-assigning of the html string, removing instances like this, which would make special character escapes hard to handle.
  2. Allow the user to pass in a TrustedTypePolicy, and then html-dom-parser would run policy.createHtml(myString) before assigning anything to innerHtml.

Keywords

security, trustedtypes, innerhtml

ValerianClerc avatar Jul 01 '25 00:07 ValerianClerc

@ValerianClerc thanks for creating this issue! I'm open to a PR that implements this as long as it's backwards compatible and doesn't cause a breaking change.

remarkablemark avatar Jul 01 '25 00:07 remarkablemark

@remarkablemark Awesome, I'll try to put something together this week!

Would you be open to me making a similar change in html-react-parser too?

ValerianClerc avatar Jul 01 '25 00:07 ValerianClerc

@ValerianClerc yes, I'm open.

For your suggested solution, will the user pass it via the option argument? Something like:

parse('<br>', {
   trustedHTML: ...
})

remarkablemark avatar Jul 01 '25 00:07 remarkablemark

Yes I think that would be the best solution, passing in via option argument.

I think "option 2" in my proposal is likely to be the simplest to implement for the codebase, since I don't think that the TrustedHTML type in "option 1" supports re-assignment/modification that is currently being used for special character handling in html-dom-parser.

So it would be something like:

const policy = window.trustedTypes.createPolicy('myPolicy', {
    createHTML: (html) => mySanitizeFunction(html)
})

parse('<br>', {
    trustedTypePolicy: policy
})

And then inside the parsing code (domparser.ts), we would do something like this:

parseFromTemplate = (html: string, trustedTypePolicy?: TrustedTypePolicy): NodeList => {
    const sanitizedHtml = trustedTypePolicy?.createHTML(html) ?? html
    template.innerHTML = sanitizedHtml;
    return template.content.childNodes;
  };

ValerianClerc avatar Jul 01 '25 00:07 ValerianClerc

@ValerianClerc sounds good

remarkablemark avatar Jul 01 '25 01:07 remarkablemark