Security of serialising/deserialising ProseMirror user input



Been sketching on an editor which will work sort-of the same way as the collaborative example, but not real-time. However, rather than working on an instance and adding steps as the collaborative example, I was thinking of serialising the document as a JSON blob, and send that between clients. This breaks for concurrent edits, but that has been thought of. :slight_smile:

In the case of a malicious user, is there any risk of an XSS/CSRF attack? In the sense that the user could send malicious JSON, which we propagate to another client, which when then deserializes the JSON blob, and have arbitrary Javascript inside there which would send credentials, or something equally malicious. Is this a worry I need to have, or is the deserialization “always” safe, given a schema which looks very much like the basic one?

One such example I can think of would be:

What do you think?



JSON, by design, doesn’t evaluate anything when deserialized, and unless you specifically add node types that render in risky ways (by putting document content in, say, onclick DOM attributes), ProseMirror should be safe.

But now that you mention it, I just thought of a cute shortcut I was using in schema-basic that does actually create a needless risk here (using attrs objects directly as DOM attribute specs, which could, if the user somehow ends up with a corrupted document, set arbitrary attributes). So thanks for making me think about this. I’ve released prosemirror-schema-basic version 1.0.1 with a fix.

Right, but, as the linked site mentions, that hole has been fixed for a while in any halfway modern browser.


You’re right, the JSON deserialisation should absolutely be safe to do, it was mostly the loading of an arbitrary document in ProseMirror I was worried about. In a sense, here we have the possibility of having corrupted documents, as in the scenario of the original post user A could forward whatever document it wants to to user B, regardless if it matches the schema or not. I can see how that is prevented through the onclick example though!

Thanks a lot for the help and clarification!