XSS without CSP bypass viewing raw XHTML files through API on IOS devices
HackerOne report #2473917 by joaxcar on 2024-04-22, assigned to GitLab Team:
Report | Attachments | How To Reproduce
Report
Summary
This report is related to #2473886 but mainly impact self-hosted instances as the CSP on the /api route is tougher than on the normal raw pages. The issues are related but the fix will not be the same.
First of all, I found a bypass to the WebKit CVE-2023-32445, which was the fix for my initial report to Apple. It turns out that they only fixed this issue for svg and xml files. Again, as I explained in my last report, this could be intentional as the HTML specs do allow browsers to ignore content-type. But I do believe they will fix this one as well, eventually. Still, I think fixing the bypass on the GitLab's side could be a good thing, as similar issues might pop up.
The issue
When visiting a site with content-type: text/plain on IOS any browser on IOS will sniff the file content instead of adhering to the content-type in these two scenarios
- The URL ends in
.xhtml - The URL does not end in a file type, but the
Content-Disposition: inline; filename="name.xhtml";header contains the filename with.xhtml
The issue exists in the API on gitlab, for example a snippet file with the filename test.xhtml can be viewed on https://gitlab.com/api/v4/snippets/<SNIPPET_ID>/raw and will get served with these headers
Content-Disposition: inline; filename="test.xhtml"; filename*=UTF-8''test.xhtml
Content-Type: text/plain; charset=utf-8
This differs from the patched raw endpoints outside of the API where the same file will get served with
Content-Disposition: inline; filename=blob
Content-Type: text/plain; charset=utf-8
Notice the filename=blob part, which will force WebKit not to sniff the `content-type' as it has no file ending.
I guess that some users might use the filename in the Content-Disposition in the API, but I see no reason for it to be served with Content-Disposition: inline. If you change inline to attachment the XSS will not work, and users will still be able to use the API for RAW content and get the filename.
What is the problem
As mentioned the CSP on gitlab.com will on the API look like this:
default-src: none;
Even if we are still able to host forms and other HTML on this page, pulling off a credential-stealing attack is harder as styles are not allowed.
But on self-hosted without proper CSP this will get XSS
<x xmlns:x="http://www.w3.org/1999/xhtml">
<x:script>alert(document.domain);</x:script>
</x>
See this video for an example
Remediation
I think Apple will fix this, but I have not gotten any response yet. Last time, it took them six months to fix, and it will still leave users who have not upgraded directly vulnerable to attacks for longer than that. Changing content-disposition from inline to attachement on .htmx files served through the API will fix this on GitLabs side.
Steps to reproduce
- Create a new snippet https://gitlab.example.com/-/snippets/new
- Add a file called
test.xthmlin the snippet and add this content
<x xmlns:x="http://www.w3.org/1999/xhtml">
<x:script>alert(document.domain);</x:script>
</x>
- Create the snippet
- Visit the snippet API route on an IOS device, use a link like this https://gitlab.example.com/api/v4/snippets/SNIPPET_ID/raw
- the script should trigger
Impact
XSS without gitlab.com CSP bypass
What is the current bug behavior?
Gitlab serves .xthml files with content-disposition: inline in the API
What is the expected correct behavior?
.xhtml files should be served with content-disposition: attachment
Impact
XSS without gitlab.com CSP bypass
Attachments
Warning: Attachments received through HackerOne, please exercise caution!
How To Reproduce
Please add reproducibility information to this section: