Open-source diagramming tools like draw.io are a staple for individuals and businesses worldwide. But with popularity comes risk: security vulnerabilities can affect countless users. In this post, we’ll do a deep dive into CVE-2022-3873, a DOM-based cross-site scripting (XSS) vulnerability that was discovered in draw.io before version 20.5.2. We’ll break down what happened, how it can be exploited, and—crucially—how to protect yourself.
What is CVE-2022-3873?
CVE-2022-3873 describes a serious vulnerability affecting versions of draw.io before 20.5.2. The bug is rooted in the client-side (DOM) code. Specifically, a flaw allowed attackers to inject malicious JavaScript via manipulated user input, which would then be executed in the browser context of users interacting with compromised diagrams or URLs.
This is a particularly dangerous type of bug known as DOM-based XSS.
What is DOM-based XSS?
DOM-based XSS is a type of cross-site scripting where the attack payload is never sent to the server but is instead executed by insecure JavaScript in the victim’s browser. This usually happens because user input is read from the URL, fragment, or other browser-exposed features, and is inserted directly into the DOM (the HTML page) without enough filtering.
Quick Example
// BAD PRACTICE: naively reading location.hash and writing to the page
document.getElementById("output").innerHTML = location.hash.slice(1);
If a user visits https://example.com/#<img src=x onerror=alert('XSS')>, the browser would render the malicious image tag and run the code!
Where Was the Bug in draw.io?
draw.io is a powerful diagram/flowchart tool. Before version 20.5.2, draw.io included logic that directly read values from the URL (for example, query parameters, fragment, etc.) and injected them into the document or processed them insecurely.
The issue was tracked here:
* GitHub Advisory Database
* osv.dev entry
Let’s walk through a theoretical vulnerable snippet (simplified for clarity)
// ATTACKER CONTROLS: 'embed' parameter in URL
const params = new URLSearchParams(window.location.search);
const userInput = params.get('embed');
// FLAW: inserting raw input into HTML (dangerous!)
if (userInput) {
document.getElementById('diagramEmbed').innerHTML = userInput;
}
Without sanitizing or escaping the userInput, attackers could craft a link that, when visited or shared, triggers arbitrary JavaScript in the context of the draw.io web app. Any person opening the link, or collaborating on the diagram, could end up running malicious code.
Craft a malicious URL:
`
https://app.diagrams.net/?embed=
Trick a user into clicking the link or opening the diagram.
3. Result: When the page loads, the code inside embed gets injected straight into the document. The browser executes the attacker’s JavaScript payload. The attacker now can steal credentials, hijack sessions, or deface diagrams.
Real-World Impact
- Session Hijacking: Attackers could steal authentication tokens with session cookies, taking over user accounts.
- Data Theft: Sensitive diagrams (maybe business secrets, infrastructure layouts) could be exfiltrated.
- Phishing Attacks: Injected scripts might show fake login screens over the diagram interface, tricking users into revealing passwords.
Simple Demonstration
Let’s assume the following simple code is present in a page using draw.io components (this illustrates the logic in older versions):
<div id="diagramEmbed"></div>
<script>
const params = new URLSearchParams(window.location.search);
const userInput = params.get('embed');
if (userInput) {
document.getElementById('diagramEmbed').innerHTML = userInput;
}
</script>
Malicious URL Example
https://vulnerable.draw.io/?embed=<img%20src=x%20onerror=alert(document.domain)>;
What happens: When that page loads, alert(document.domain) pops up, proving code execution.
The Fix
After reporting, the draw.io team released version 20.5.2 which properly sanitized inputs and closed down the vector.
Escaping HTML: Using textContent instead of innerHTML where possible.
- Sanitizing input: Filtering/escaping any user-supplied data reflected into the DOM.
After
document.getElementById('diagramEmbed').textContent = userInput;
Now, even if userInput contains HTML/JS, it appears as harmless text.
Official advisory:
https://github.com/advisories/GHSA-6m6v-x5g5-88c7
Draw.io changelog:
https://github.com/jgraph/drawio/releases/tag/v20.5.2
Detailed writeup on DOM-based XSS:
https://portswigger.net/web-security/cross-site-scripting/dom-based
Summary
CVE-2022-3873 is a powerful reminder that even the best tools can fall victim to classic web security problems like cross-site scripting—especially in complex, user-driven applications. Staying updated and practicing good sanitation habits are key to keeping your data, your users, and yourself safe.
Timeline
Published on: 11/07/2022 11:15:00 UTC
Last modified on: 11/08/2022 04:17:00 UTC