Page MenuHomePhabricator

Allow Javascript files from Wikimedia GitLab to be loaded as scripts in Wikimedia wikis
Closed, DeclinedPublicFeature

Description

Feature summary (what you would like to be able to do and where):
I would like to run userscripts stored on Wikimedia GitLab on Wikimedia wikis.

Use case(s) (list the steps that you performed to discover that problem, and describe the actual underlying problem which you want to solve. Do not describe only a solution):

I tried including https://gitlab.wikimedia.org/lectrician1/discographies-js/-/blob/main/discographies2.js in my common.js but got this error:
The resource from “https://gitlab.wikimedia.org/lectrician1/discographies-js/-/raw/main/discographies2.js” was blocked due to MIME type (“text/plain”) mismatch (X-Content-Type-Options: nosniff).

Benefits (why should this be implemented?):
Userscripts can be stored and contributed from GitLab which is a significantly better software management platform than storing them on Mediawiki.

Event Timeline

Looks CORS-related. Should be a simple fix to add gitlab.wikimedia.org to our allow list.

Any ideas for proper Phabricator tag?

Reedy subscribed.

Noting this isn't something we currently allow from Gerrit (or any of it's code viewing UIs) nor did we allow from Diffusion on Phabricator.

I wonder if a better approach would be to have an extension just for scripts that bundles them up into RL modules and is deployed in the normal way.

hashar subscribed.

I am removing the GitLab tag since this is really about MediaWiki-extensions-Gadgets


Gitlab serves raw content with Content-Type: text/plain. The additional X-Content-Type-Options: nosniff instructs browsers to not try to interpret it as a script or stylesheet. It literally works as expected.

If I remember properly, Internet Explorer would attempt to find the mime type of a file automatically. A potential attack would have been to upload a '.jpg` file containing a JavaScript and link it as a script in some editable content. nosniff explicitly asks the browser to NOT do any autodetection.

There is a long range of ideas to improve hosting Gadgets:

If I remember properly, Internet Explorer would attempt to find the mime type of a file automatically. A potential attack would have been to upload a '.jpg` file containing a JavaScript and link it as a script in some editable content. nosniff explicitly asks the browser to NOT do any autodetection.

So the original attack you are thinking of was autodetection of html (or other "executable mime types" like svg) not js, and was all about things on the same origin and loading them as top level documents. It is generally assumed that once you can link a script all is lost (major exception being certain csp configs which we dont use). In any case, it is mostly not relavent anymore on modern browsers.

For cross origin attacks, the general assumption (barring certain CSP configs), is that the attacker controls all headers, because they can just choose any host on the entire internet. The primary benefit of nosniff in a cross origin scenario is not to prevent XSS but to prevent leaking data - that is to protect the host of the file being included as js, not the host of site including the script. Principly it is to protect against XSSI (which is when you execute a file as if it was js [may or not actually be js], and hope you can reveal something about its contents by observing side effects) and to a lesser extent to protect against spectre type attacks (depending on some other factors, setting no-sniff may prevent the file in question from being loaded into the same process as js runs in, which prevents spectre).

Anyways, point is, since files on gitlab aren't secret, and since we are not generally using csp to control where js is allowed to come from, imho, there probably isn't much risk as labelling the js ones as content-type: text/javascript. Whether we want to do that is an entirely different question.

Novem wrote:

Looks CORS-related. Should be a simple fix to add gitlab.wikimedia.org to our allow list.

Just to clarify this isn't cors related. You don't need a site to be on the CORS list to execute js from it. You only need it to be on the cors list to "read" the js. [Assuming no Cross-origin-resource-policy or cross-origin-embedder-policy headers are in play, which changes the rules]

As a response to @Tgr's concern

Hotlinking scripts from another site doesn't seem great if one uses URLs whose content can change (ie. git branches/tags, not commit IDs).

at T321448#8340452

Users could create a JS wiki page that would load the script located at GitLab. If the script URL changes at GitLab, all they would need to do is update the URL at the wiki page.

This clearly isn't the most optimal solution, so another solution could be to use Extension:ExternalRedirect on a wiki page that would redirect to the Wikimedia GitLab script URL. Obviously, the Wikimedia GitLab site would be set as the only allowed redirect addresses.

mmartorana changed the task status from Open to In Progress.Nov 14 2022, 12:25 PM
mmartorana triaged this task as Low priority.
mmartorana subscribed.

Hi - The Security-Team has reviewed this proposed feature, and our feedback is that even though we agree in using Gitlab as a central repository for userscripts and gadgets would be a good idea, we don't suggest to achieve this by removing the nosniff option, as we would be exposed to several kinds of attacks such as: MIME confusion attacks and unauthorized hotlinking. The risk of doing this would be medium.

Please see other discussion around this issue for possible solutions:

@mmartorana is there a reason why we can't just label raw JS files on GitLab as content-type: text/javascript like @Bawolff suggested?

@mmartorana is there a reason why we can't just label raw JS files on GitLab as content-type: text/javascript like @Bawolff suggested?

Because the software does not support that behavior:

The functional equivalent of the mime-type part of this request has been rejected as WONTFIX upstream at GitLab multiple times:

I suppose it wouldn't be too hard to add either via a downstream patch or web server config. There are several potential issues though:

  • It would require a second domain, and be limited to that domain, otherwise it could be trivially used for XSS attacks against Gitlab itself.
  • It would have to be limited to URLs with static content (ie. which contain a commit ID), otherwise an attacker can take over the script owner's Gitlab account and use it to launch an XSS against Wikipedia. We have seen such attacks via Wikimedia account takeover for on-wiki hosted scripts, I don't think we'd want to worry about another authentication system (which we have less control about) being added to the threat surface.
    • Because you have to do that, it wouldn't allow any kind of managed rollout of upgrades, you'd have to go around, find every wiki which links to an old version and change the links. It would be basically equivalent to copy-pasting the file content to a wiki page on every wiki using the script, which is an existing antipattern that script maintainers have been trying to move away from in various ways.
  • It could be used to host XSS attack vectors against third parties. Not a big risk I suppose, as so many other places can be used for that, but if it does happen (possibly because the attacker's intent is to damage Wikimedia's reputation), it could get the site on malware lists etc.

On the net IMO it would create more problems than it would solve.

It would require a second domain, and be limited to that domain, otherwise it could be trivially used for XSS attacks against Gitlab itself.

Could you elaborate about a second domain and give an example of a XSS attack against Gitlab? To me, enabling pages to share themselves as Javascript is no different than Mediawiki being able to do the same thing so I don't understand this.

It would have to be limited to URLs with static content (ie. which contain a commit ID), otherwise an attacker can take over the script owner's Gitlab account and use it to launch an XSS against Wikipedia. We have seen such attacks via Wikimedia account takeover for on-wiki hosted scripts

Since this is already a current security vulnerability, we're not really changing the status quo.

I don't think we'd want to worry about another authentication system (which we have less control about) being added to the threat surface.

Then we should require a Wikimedia account to sign into Gitlab. Then that way we only have to control one account.

It could be used to host XSS attack vectors against third parties. Not a big risk I suppose, as so many other places can be used for that, but if it does happen (possibly because the attacker's intent is to damage Wikimedia's reputation), it could get the site on malware lists etc.

Could we set the raw Javascript resources to have Access-Control-Allow-Origin: en.wikipedia.org wikidata.org etc. to solve this?

Hi @Lectrician1 - I wanted to point out that the Security-Team is not disapproving the change; we have just rated it as medium risk.

This configuration change would need to be agreed to by GitLab's ostensible maintainers: the Release-Engineering-Team.

Furthermore, it would imply establishing using GitLab as a CDN, which we haven't done in Gerrit, and isn't a use-case that was previously discussed when deciding on GitLab as a successor to Gerrit.

It would also expand the attack surface for imported Javascript files to Mediawiki when we would prefer maintaining such scripts within a versioning system along with a more formalised deployment process.

Could you elaborate about a second domain and give an example of a XSS attack against Gitlab? To me, enabling pages to share themselves as Javascript is no different than Mediawiki being able to do the same thing so I don't understand this.

Sorry, you are right, you'd need to enable some HTML content type for initiating an XSS attack. But enabling JS would still mean that Gitlab's own CSP headers would be ineffective against an XSS attack if some other vulnerability allows loading an arbitrary URL, as they don't block same-origin JS files.

(Disabling the nosniff header would potentially allow XSS attacks, but that's not that relevant for this task.)

Then we should require a Wikimedia account to sign into Gitlab. Then that way we only have to control one account.

Gitlab uses developer accounts (the same system as Gerrit, Toolforge, Cloud VPS etc). Merging two different SSO systems is a massive undertaking that's not happening anytime soon, probably not ever, given that Wikimedia SUL is a fairly open system with risky security practices, while developer accounts have much higher security stakes.

Could we set the raw Javascript resources to have Access-Control-Allow-Origin: en.wikipedia.org wikidata.org etc. to solve this?

As far as I can see CORS headers aren't really relevant to this. You don't need CORS headers to be able execute a foreign script; you only need it for various relatively unimportant debugging-type activities (and minor security risks) like seeing error stack traces or request timing.


Anyway, serving JS straight from Gitlab is not strictly impossible but inferior in pretty much every way to serving it from MediaWiki. Less performant (no ResourceLoader minification or client-side store, less control over cache headers), less secure (if nothing else, because we have much less Gitlab expertise in our community than MediaWiki expertise, so we have less control over it and haven't built out monitoring to the same degree), less manageable (e.g. in terms of how do you deploy a new version of your script to the wiki). Even just having a bot copy over Gitlab files to MediaWiki gadget files would work way better than hotlinking. I suggest declining this task.

.

Could we set the raw Javascript resources to have Access-Control-Allow-Origin: en.wikipedia.org wikidata.org etc. to solve this?

As far as I can see CORS headers aren't really relevant to this. You don't need CORS headers to be able execute a foreign script; you only need it for various relatively unimportant debugging-type activities (and minor security risks) like seeing error stack traces or request timing.

This is possibly bordering into offtopic, but presumably what @Lectrian1 meant was the CORS header in combination with Cross-Origin-Resource-Policy: same-origin

This is possibly bordering into offtopic, but presumably what @Lectrian1 meant was the CORS header in combination with Cross-Origin-Resource-Policy: same-origin

Looking at the fetch spec, it doesn't seem like it's possible to combine those two headers, CORP would just take precedence over CORS.

Less performant (no ResourceLoader minification or client-side store, less control over cache headers

Well then make a secondary site where people can "deploy" their scripts stored in GitLab and it will serve that will serve a minified version of the script with configurable cache headers. If we do that then we will also be able to control what content gets served.

less manageable (e.g. in terms of how do you deploy a new version of your script to the wiki)

You push a new version to master, just like what you do with current Mediawiki user scripts...

Even just having a bot copy over Gitlab files to MediaWiki gadget files would work way better than hotlinking.

A bot to copy over a script to every Wikimedia wiki seems quite wasteful and unnecessary when we have the ability to serve scripts from a Wikimedia-controlled site that any wiki can easily use by fetching from it.

We can host scripts at another domain like cdn.wikimedia.org. Gitlab have Gitlab Pages feature and we may make use of it.

thcipriani subscribed.

Declining as product owner of GitLab.

I worry about maintenance burden—blobs are set with MIME-type text/plain explicitly in GitLab's code so to change this, we would have to change the code

This is a problem for our small team as:

  • GitLab secruity releases come without warning and any one might break this compatibility with this change
    • And a choice between securing gitlab and breaking all gadgets is not one I ever want to be faced with
  • Our team would be saddled with the responsibility to mitigate the risk of XSS while overriding existing upstream protections against it

Further, Gerrit, GitLab, and Phabricator are developer services, this is a service for end-users on wiki. This comes with a different number of 9s than we currently offer or are resourced to provide.

So, while we could do this, it is my belief that we on Release-Engineering-Team could not do it well. And so—I'm declining.


There are a number of good suggestions on this task that we can look at. And I believe GitLab is a great place to host Gadget and Userscript development.

@thcipriani What about hosting the resources in another domain? such as https://lectrician1.cdn.wikimedia.org/discographies-js/discographies2.js

  • The URL provided by GitLab Pages (once enabled) should be stable and any MIME type may be supported
  • "This comes with a different number of 9s" - userscripts are optional and not loaded by default. At least serving them from a production domain (such as gitlab.wikimedia.org) is better than serving them from Cloud Services.