[GitLab] Store XSS when Processing Mermaid Content in a Markdown File ($3000 USD)
Mermaid is a markdown-like syntax for generating flowcharts and is supported by GitLab’s markdown parser. The Mermaid parser itself can be provided various configuration options at initialization time, and then some of those can be overloaded by inline directives. There are some directives that cannot be overloaded, such as secure
and securityLevel
as that would defeat their purpose. One configuration option that could be overloaded by an inline directive is htmlLabels
which leads to the abilit to place arbitrary HTML in the labels by including the following line:
%%{init: {"flowchart": {"htmlLabels": "false"}} }%%
Content Security Policy (CSP) Bypass
GitLab used the following CSP:
script-src 'self' 'unsafe-inline' 'unsafe-eval' https://assets.gitlab-static.net https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ https://www.recaptcha.net/ https://apis.google.com 'nonce-<nonce>'
The problem bypass in this case was to take advantage of the ability to serve files (pipeline artifacts) on the same domain, and these files were served with an appropiate Content-Type
header (gets around X-Content-Type: nosniff
). While they were served with a Content-Disposition: attachment
meaning they couldn’t be used in some cases, here it could be included as a script source.
The last trick involved was that you cannot use a .innerHTML
write to inject a <script>
tag, so the author opted to inject an <iframe srcdoc='<script ...></script></iframe>'