Exploiting Zoom whiteboard via the clipboard. Nice find from @spaceraccoon

https://spaceraccoon.dev/analyzing-clipboardevent-listeners-stored-xss/

I Hope This Sticks: Analyzing ClipboardEvent Listeners for Stored XSS

When is copy-paste payloads not self-XSS? When it’s stored XSS. Recently, I reviewed a Zoom’s code to uncover an interesting attack vector.

@gaz @spaceraccoon Nice writeup!

Looking at this with a browser's hat on, I wonder what we could do to make the `convertToText()` mechanism go away. The new `Element.setHTML()` method aims to handle element nodes being added to the DOM. It doesn't do much for attributes... I wonder if that's a pattern common-enough for there to be something here we should be generalizing?

@gaz @spaceraccoon That said, it's a somewhat straightforward wrapper in userland:

```
let temp = document.createElement('div');
temp.setHTML(data);
el.attribute = temp.innerHTML;
```

/cc @freddy

@mikewest @gaz @spaceraccoon @freddy from what I understand, the issue was not due to transporting HTML in an attribute, but rather that later regexes were used to transform that HTML into text-ish form. That processed text later skipped sanitization via DOMPurify (and it would just as likely skip setHTML?). Perhaps DOMPurify wasn't used because it would destroy some of the legitimate payload, it's not clear, but to me it looks like an 'unchecked flows to raw sinks are possible' problem, and not a 'sanitizer is missing' problem. The authors knew untrusted HTML needed sanitizing, they just didn't sanitize there for some reason.

@koto @gaz @spaceraccoon @freddy My read of the last step was that they _did_ use `convertToText()` as a sanitizer for input to the `dangerouslySetInnerHTML` sink, but that their implementation was a regex that didn't handle multi-line strings. :)

Obviously removing the use of the dangerous sink would be better. But given that developers gonna develop, I wonder whether there's anything we can learn from this for the Sanitizer API.

@mikewest @koto @spaceraccoon @freddy Yep Mike is correct because they used "." without /m it wouldn't match new lines.

@gaz @mikewest @spaceraccoon @mikewest @gaz @spaceraccoon I second @koto 's interpretation in that they used DOMPurify in some places, but not in others. imho, the important piece for us to learn is:

A great sanitizer can't help if you forget to use it. A document-wide policy like CSP could enforce things (see Trusted Types).

@freddy @gaz @mikewest @spaceraccoon Yeah, easy sanitizer so you don't have to think about your configuration, dependencies, and CSP/TT so you never forget to use it. Now let's just convert all the web to that pattern :)