Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Endless loop of DOMParser.parseFromString when used with Trusted Types polyfill #563

Closed
orazioedoardo opened this issue Nov 15, 2024 · 2 comments
Labels

Comments

@orazioedoardo
Copy link

This same issue has been raised at cure53/DOMPurify#1027, but they believe it's not a DOMPurify issue but rather an issue with the polyfill.

Background & Context

When trying to use DOMPurify in conjunction with the trustedTypes polyfill, the HTML is not sanitized but rather seems to run into an endless loop as if DOMPurify does not set its "dompurify" policy. Not sure if it's a DOMPurify issue, or an issue with the polyfill, or if I'm using it wrong, sorry if this is the wrong place to ask.

Input

This is the sample JavaScript code which then I bundle with webpack.

import { trustedTypes, TrustedTypeConfig, TrustedTypesEnforcer } from "trusted-types";
import DOMPurify from "dompurify";

let trustedTypesObject;

if (window.trustedTypes && trustedTypes.createPolicy) {
    trustedTypesObject = window.trustedTypes;
} else {
    trustedTypesObject = trustedTypes;
    const config = new TrustedTypeConfig(false, true, ["default", "dompurify"], false);
    const enforcer = new TrustedTypesEnforcer(config);
    enforcer.install();
}

trustedTypesObject.createPolicy("default", {
    createHTML: (string, type) => {
        console.warn("Created a '" + type + "' object.");
        return DOMPurify.sanitize(string, { RETURN_TRUSTED_TYPE: false });
    },
});

Given output

Example output from Safari, caught in an endless loop of thousands of DOMParser.parseFromString sanitization instances. At some point it ends but I believe the browser is doing it. If I try it in Chrome, it never ends and hangs the tab.

tt

Expected output

Expected a TrustedHTML object.

@koto
Copy link
Member

koto commented Nov 15, 2024

DOMPurify initializes itself on import, and at that time the polyfill isn't installed yet, so it indeed doesn't create a policy, and is using regular DOM sinks, which triggers an infinite loop from the default policy.

The solution is likely to import DOMPurify once the polyfill is installed (e.g. with a dynamic import).

@koto koto closed this as completed Nov 15, 2024
@orazioedoardo
Copy link
Author

orazioedoardo commented Nov 15, 2024

Thank you very much, your reply headed me to the right direction, here's the solution for future readers:

import { trustedTypes, TrustedTypeConfig, TrustedTypesEnforcer } from "trusted-types";

if (!window.trustedTypes || !window.trustedTypes.createPolicy) {
    window.trustedTypes = trustedTypes;
    const config = new TrustedTypeConfig(false, true, ["default", "dompurify"], false);
    const enforcer = new TrustedTypesEnforcer(config);
    enforcer.install();
}

import("dompurify").then(({ default: DOMPurify }) => {
    window.trustedTypes.createPolicy("default", {
        createHTML: (string, type) => {
            const sanitized = DOMPurify.sanitize(string, { RETURN_TRUSTED_TYPE: false });
            console.warn("Created a '" + type + "' object.")
            return sanitized;
        }
    });
});

Unfortunately webpack would load dompurify from a chunk but since the URL is not a TrustedScriptURL the import would fail. I tried creating a default policy with the createScriptURL and the module loaded but then I couldn't add other policies because duplicates are not allowed. Chicken and egg problem. To get out of it I simply disabled chunks in webpack, which I prefer anyway:

const webpack = require('webpack');
module.exports = {
  // ...
  plugins: [
    new webpack.optimize.LimitChunkCountPlugin({
      maxChunks: 1,
    }),
  ],
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants