Skip to content

XSS without CSP bypass viewing raw XHTML files through API on IOS devices

Please read the process on how to fix security issues before starting to work on the issue. Vulnerabilities must be fixed in a security mirror.

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

  1. The URL ends in .xhtml
  2. 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

XSS_NO_CSP.mov

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

  1. Create a new snippet https://gitlab.example.com/-/snippets/new
  2. 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>  
  1. Create the snippet
  2. Visit the snippet API route on an IOS device, use a link like this https://gitlab.example.com/api/v4/snippets/SNIPPET_ID/raw
  3. 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: