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.xthml
in 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: