The Special:ApiSandbox page is vulnerable to XSS when visiting a specific URL. User interaction (pressing a button) is required.
Reproduction Steps
- Go to https://en.wikipedia.beta.wmflabs.org/wiki/Special:ApiSandbox#action=parse&text=%3Cpre%3E%3C%2Fpre%20%20%3E%3Cimg%20src%3D%22%23%22%20onerror%3Dalert%281%29%3E%3Cpre%3E%3C%2Fpre%3E&prop=wikitext&format=abc
- Click "Make request"
Explanation
The following steps happen after pressing the button:
- If an invalid format is provided to Special:ApiSandbox (in my example url, abc), the wrappedhtml param is not set to 1 in the API request: https://github.com/wikimedia/mediawiki/blob/97ca97636ca3ea803ea7e8bb59c814988a198fee/resources/src/mediawiki.special.apisandbox/ApiSandbox.js#L307-L315
- This param is queried by the API backend and mIsWrappedHtml is set to false: https://github.com/wikimedia/mediawiki/blob/97ca97636ca3ea803ea7e8bb59c814988a198fee/includes/api/ApiFormatBase.php#L64
- Since mIsWrappedHtml is set to false, the content type of the response is not set to text/mediawiki-api-prettyprint-wrapped: https://github.com/wikimedia/mediawiki/blob/97ca97636ca3ea803ea7e8bb59c814988a198fee/includes/api/ApiFormatBase.php#L222
- Back in the ApiSandbox JS, an if condition in the response handler evaluates to false, since the content type is not set to text/mediawiki-api-prettyprint-wrapped: https://github.com/wikimedia/mediawiki/blob/97ca97636ca3ea803ea7e8bb59c814988a198fee/resources/src/mediawiki.special.apisandbox/ApiSandbox.js#L439
- An else if branch then evaluates to true if the entire API response JSON has any <pre> element inside it: https://github.com/wikimedia/mediawiki/blob/97ca97636ca3ea803ea7e8bb59c814988a198fee/resources/src/mediawiki.special.apisandbox/ApiSandbox.js#L457
- The pre tag is then inserted into HTML without sanitization: https://github.com/wikimedia/mediawiki/blob/97ca97636ca3ea803ea7e8bb59c814988a198fee/resources/src/mediawiki.special.apisandbox/ApiSandbox.js#L458
In my example, I used the parse API with the wikitext prop to get back exactly what I submitted in the text parameter. However, any API endpoint that can return unsanitized HTML anywhere within its JSON response (e.g. querying the content of revisions or system messages) can be used for this.
Further information
Browser: Firefox 138.0.3 on Fedora 42

