HTML SanitizerLoading saved progress…

HTML Sanitizer

When you render HTML that came from a user — a comment, a profile bio, a chat message — you can't trust it. A <script> tag or an onclick="..." attribute slipped into that markup runs in your page with your user's session. A sanitizer defends against this by allowing only a known-safe set of tags and attributes through and removing everything else. You'll implement a simplified one that cleans a DOM subtree in place.

Signature

type Options = {
  allowedTags: string[];        // tag names to keep, e.g. ['p', 'a', 'b']
  allowedAttributes: string[];  // attribute names to keep, e.g. ['href', 'id']
};

function htmlSanitizer(root: Element, options: Options): Element;

You receive a root element whose subtree may contain untrusted markup. Mutate that subtree in place and return the same root. Comparisons of tag and attribute names are case-insensitive.

Examples

const root = document.createElement('div');
root.innerHTML = '<p onclick="steal()">hi</p><script>alert(1)</script>';

htmlSanitizer(root, { allowedTags: ['p'], allowedAttributes: [] });
root.innerHTML;
// → '<p>hi</p>'
// the <script> is gone; the <p> stays but its onclick is stripped
const root = document.createElement('div');
root.innerHTML = '<a href="/home" onclick="evil()">go</a>';

htmlSanitizer(root, { allowedTags: ['a'], allowedAttributes: ['href'] });
root.innerHTML;
// → '<a href="/home">go</a>'   (href kept, onclick dropped)

Notes

  • Disallowed tags are removed entirely. If an element's tag is not in allowedTags, remove the element and its whole subtree. Don't unwrap it or keep its children.
  • Disallowed attributes are stripped from kept elements. On every element you keep, remove any attribute whose name is not in allowedAttributes. This is what neutralizes onclick, onerror, style, and friends.
  • Recurse to every depth. Untrusted markup can hide a <script> or an onerror arbitrarily deep in the tree — you must clean the whole subtree, not just direct children.
  • Case-insensitive. Treat DIV and div, HREF and href, as the same name.
  • In place. Mutate the existing tree and return the same root; don't build and return a new one.
Loading editor…