cure53 / DOMPurify

DOMPurify - a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG. DOMPurify works with a secure default, but offers a lot of configurability and hooks. Demo:
https://cure53.de/purify
Other
13.77k stars 708 forks source link

Sanitization Issue: Comments Removed Despite ADD_TAGS Configuration #932

Closed agnijalam closed 6 months ago

agnijalam commented 6 months ago

Hi I am attempting to sanitize HTML content for a specific functionality, preserving AngularJS attributes and comments tags. However, despite specifying ADD_TAGS:['#comment'] in the configuration, the comment section is still being sanitized

Code Sample:

const config = {
    WHOLE_DOCUMENT: true,
    ADD_ATTR: ['ng-if','ngmodel','ng-repeat','onclick','ng-model','ng-options','ng-click'],
    ADD_TAGS:['#comment']
};

<form method="post" action="test.do">
    <li>
        <label >First Name:</label>
        <input type='text' name="input1" />
    </li>
    <!--
    2. Radio buttons 

    <<< Code Snippet >>>

    <table cellspacing="0" cellpadding="0" border="0">
        <tbody><tr  ng-repeat="value in input2['test'].values">
            <td  valign="top" nowrap="true">
                <input type='radio' ng-model="form.input2['test'][0]" 
                    name="form.input2['test'][0]" ng-value="value" />
                <label style="text-align:left" >{{value}}</label>
            </td>
        </tr>
        </tbody>
    </table>
    <<< Code Snippet >>>
    -->
</form>

Expected Behavior: The comments within the HTML content should be preserved during the sanitization process according to the provided configuration.

Steps to Reproduce:

  1. Apply the provided configuration for sanitizing HTML content.
  2. Attempt to sanitize HTML content containing comments as demonstrated in the provided code sample.
  3. Observe that the comments are not preserved as expected.

    Additional Content: I understand that preserving comments during HTML sanitization might be considered a special case or a corner case. However, preserving comments is essential for the functionality and readability of the HTML content in this particular scenario.

Request for Assistance: I would appreciate any insights or suggestions on how to tackle this issue. If there are alternative approaches or additional configuration options that can be utilized to achieve the desired outcome of preserving comments while sanitizing HTML content, please advise accordingly.

Current Approach: At present, the configuration includes ADD_TAGS:['#comment'] in an attempt to preserve comments. However, despite this configuration being specified, the comments are still being sanitized.

Open to Suggestions: I am open to exploring alternative solutions or workarounds that would enable the preservation of comments without compromising the security and integrity of the sanitization process. Any guidance or recommendations on how to address this issue would be greatly appreciated

cure53 commented 6 months ago

Hey there, thanks for filing this :slightly_smiling_face:

Sadly, we have to be very strict with comments wrapping HTML as this causes bypasses when dealing with mixed content. You can likely tackle that problem with a hook, but there might be an XSS risk then.

cure53 commented 6 months ago

We are currently looking into making this controllable via config, likely the next release will allow to control that behavior a bit better.

cure53 commented 6 months ago

Monday, a new release will come and make sure that the aggressive comment removal, which is only needed when XML is being sanitized and later used in HTML, can be controlled. That should fix the issue.

agnijalam commented 6 months ago

@cure53, I have validated it with 3.1.0 and it is reproducible. used Configuration:

 const config = {
    WHOLE_DOCUMENT: true,
    ADD_ATTR: ['ng-if','ngmodel','ng-repeat','onclick','ng-model','ng-options','ng-click'],
    ADD_TAGS:['#comment'], USE_PROFILES: { html: true }
};

Html content used for testing:

<form method="post" action="test.do">
    <li>
        <label >First Name:</label>
        <input type='text' name="input1" />
    </li>
    <!--
    2. Radio buttons 

    <<< Code Snippet >>>

    <table cellspacing="0" cellpadding="0" border="0">
        <tbody><tr  ng-repeat="value in input2['test'].values">
            <td  valign="top" nowrap="true">
                <input type='radio' ng-model="form.input2['test'][0]" 
                    name="form.input2['test'][0]" ng-value="value" />
                <label style="text-align:left" >{{value}}</label>
            </td>
        </tr>
        </tbody>
    </table>
    <<< Code Snippet >>>
    -->
</form>

Please let me know if I missed anything, thanks

cure53 commented 6 months ago

Check the new config option we offer, that will fix it:

https://github.com/cure53/DOMPurify?tab=readme-ov-file#general-settings

agnijalam commented 6 months ago

Hi @cure53, I apologize for the repeated inquiry. Despite configuring the SAFE_FOR_TEMPLATES setting to true. I am still able to reproduce an issue. Below, I have provided the sample code and input. could you please assist me in resolving this

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Textarea Sanitization</title>
<!-- Include DOMPurify library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.1.0/purify.min.js" ></script>
</head>
<body>

<textarea id="textInput" rows="4" cols="50"></textarea><br>
<button onclick="sanitizeAndWrite()">Sanitize Content</button>

<script>
function sanitizeAndWrite() {
  var textarea = document.getElementById("textInput");
  var currentText = textarea.value;
const config = { ADD_ATTR: ['ng-if','ngmodel','ng-repeat','ng-model','ng-options','ng-click'], ADD_TAGS:['#comment'],   SAFE_FOR_TEMPLATES: true};  
  var sanitizedText = DOMPurify.sanitize(currentText,config);
  console.log(DOMPurify.removed);
  textarea.value = sanitizedText; 
}
</script>
</body>
</html>

Input for sanitization:

<form method="post" action="test.do">
    <li>
        <label >First Name:</label>
        <input type='text' name="input1" />
    </li>
    <!--
    2. Radio buttons 

    <<< Code Snippet >>>

    <table cellspacing="0" cellpadding="0" border="0">
        <tbody><tr  ng-repeat="value in input2['test'].values">
            <td  valign="top" nowrap="true">
                <input type='radio' ng-model="form.input2['test'][0]" 
                    name="form.input2['test'][0]" ng-value="value" />
                <label style="text-align:left" >{{value}}</label>
            </td>
        </tr>
        </tbody>
    </table>
    <<< Code Snippet >>>
    -->
</form>
cure53 commented 6 months ago

Please try this one as well - that is the actual new one, sorry for being unclear earlier: SAFE_FOR_XML

agnijalam commented 6 months ago

it works, Thanks