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
14.04k stars 727 forks source link

[feature] request: add `isDirty()` or similar method to determine code cleanliness #1026

Open tonypapousek opened 3 days ago

tonypapousek commented 3 days ago

This issue proposes a feature that would:

Background & Context

I'm working on a project that takes user input as HTML and renders it elsewhere. There's a requirement to toss any input that would require sanitization, instead of just sanitizing+saving it. I'd like to augment an existing function that does this with an additional check using DOMPurify.

Because of how the output is built, something like this can't work reliably:

  const sanitized = DOMPurify.sanitize(html, config);
  const isMaybeClean = html === sanitized; // throw if false

From what I can tell, there aren't enough hooks to accurately determine if DOMPurify had changed anything. Detecting unexpected attributes and elements works well enough with hooks, but escaped strings and the like remain a head-scratcher. I might just be missing something in the docs, though.

Feature

const config: DOMPurify.Config = {
  ALLOWED_TAGS: ['html', 'body', 'div', 'a'],
  ALLOWED_ATTR: ['href', 'alt', 'class', 'id', 'style', 'title'],
};

DOMPurify.isDirty(`<div>text</div>`, config); // true
DOMPurify.isDirty(`<body><div>text</div></body>`, config); // true
DOMPurify.isDirty(`<p>text</p>`, config); // false, `p` tag not in `ALLOWED_TAGS`
DOMPurify.isDirty('javascript:"/*\'/*`/*--></noscript></title></textarea></style></template></noembed></script><html \\" onmouseover=/*<svg/*/onload=alert()//>', config) // false

PS: Thanks for maintaining this package!

n-rowe commented 3 days ago

Could you not use DOMPurify.removed

Using your sanitize example:

const sanitized = DOMPurify.sanitize(html, config);
// const isMaybeClean = html === sanitized; // throw if false
const isClean = DOMPurify.removed.length ===  0;

Briefly mentioned in the README: https://github.com/cure53/DOMPurify?tab=readme-ov-file#okay-makes-sense-lets-move-on

It does state not to use it for security decisions, so a dedicated and supported isDirty function may be better

cure53 commented 3 days ago

That sounds like a good idea. Anyone wants to spin up a PR?