| <!doctype html> |
| <html> |
| <head> |
| <script src="../dist/purify.js"></script> |
| <!-- Grab the latest version of MentalJS --> |
| <script src="./lib/Mental.js"></script> |
| </head> |
| <body> |
| <!-- Our DIV to receive content --> |
| <div id="sanitized"></div> |
| <div id="test"></div> |
| <!-- Now let's sanitize that content --> |
| <script> |
| 'use strict'; |
| |
| // Initialize MentalJS |
| MentalJS().init({ dom: true, parseInnerHTML: filter }); |
| |
| // Specify dirty HTML |
| const dirty = ` |
| abc<script>alert('from script:'+location)<\/script> |
| <img src="xyz" onerror="document.getElementById('test').innerHTML='<img src=123 onerror=alert(/from_innerhtml/);';" /> |
| <img src="xyz" onerror="alert('from img:'+location)"> |
| <img src="xyz" onload="alert\`3\`"> |
| <img src="xyz" onload=""> |
| <script src=//evil.com><\/script> |
| <script>alert\`4\`<\/script> |
| <script src=//evil.com>alert(5)<\/script> |
| <svg><script xlink:href=//evil.com>alert(6)<\/script></svg> |
| <svg><script href="//evil.com">123<\/script><p> |
| `; |
| |
| // Add a hook to sanitize all script content with MentalJS |
| DOMPurify.addHook('uponSanitizeElement', (node, data) => { |
| if (data.tagName === 'script') { |
| const script = node.textContent; |
| if (!script || 'src' in node.attributes |
| || 'href' in node.attributes |
| || 'xlink:href' in node.attributes) { |
| return node.parentNode.removeChild(node); |
| } |
| try { |
| const mental = MentalJS().parse({ |
| options: { eval: false, dom: false }, |
| code: script |
| }); |
| const scriptNode = document.createElement('script'); |
| scriptNode.appendChild(document.createTextNode(mental)); |
| document.head.appendChild(scriptNode); |
| return node.parentNode.removeChild(node); |
| } catch (e) { |
| return node.parentNode.removeChild(node); |
| } |
| } |
| }); |
| |
| // Add a hook to sanitize all allow-listed events with MentalJS |
| DOMPurify.addHook('uponSanitizeAttribute', (node, data) => { |
| if (data.attrName.match(/^on\w+/)) { |
| const script = data.attrValue; |
| try { |
| return data.attrValue = MentalJS().parse({ |
| options: { eval: false, dom: false }, |
| code: script |
| }); |
| } catch (e) { |
| return data.attrValue = ''; |
| } |
| } |
| }); |
| |
| function filter(dirty) { |
| const config = { |
| ADD_TAGS: ['script'], |
| ADD_ATTR: ['onclick', 'onmouseover', 'onload', 'onunload', 'onerror'] |
| }; |
| const clean = DOMPurify.sanitize(dirty, config); |
| return clean; |
| } |
| |
| document.getElementById('sanitized').innerHTML = filter(dirty); |
| </script> |
| </body> |
| </html> |