[GitLab] Store XSS when Processing Mermaid Content in a Markdown File ($3000 USD)

We discussed this vulnerability during Episode 95 on 01 November 2021

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>'