Page MenuHomePhabricator

CVE-2025-62667: Stored XSS through article extracts in GrowthExperiments
Closed, ResolvedPublicSecurity

Description

In the GrowthExperiments extension, article extracts containing unsanitized user-provided content are inserted into the DOM as HTML, allowing for stored XSS by including a payload in an article.

Reproduction

Despite trying various methods for mocking suggested edits linked at https://www.mediawiki.org/wiki/Extension:GrowthExperiments/developer_setup#Suggested_Edits, I was unable to properly set up suggested edits in my development environment (partially due to aspects such as https://addlink-simple.toolforge.org being dead).
Therefore, the following POC requires modifying JS.

  1. Configure GrowthExperiments to pull data from enwiki:
$wgGENewcomerTasksConfigTitle = 'mw:Growth/Personalized_first_day/Newcomer_tasks/Prototype/templates/en.json';
$wgGENewcomerTasksRemoteApiUrl = 'https://en.wikipedia.org/w/api.php';
$wgGERestbaseUrl = 'https://en.wikipedia.org/api/rest_v1';
  1. Edit the modules/ext.growthExperiments.DataStore/GrowthTasksApi.js file (this line) and apply the following diff:
-const encodedTitle = formatTitle( title );
+const encodedTitle = 'Div_and_span';

This forces GrowthExperiments to always retrieve the extract from https://en.wikipedia.org/wiki/Div_and_span instead of the page shown in the edit suggestion.

  1. Make sure you have Special:Homepage enabled in your user preferences
  2. Go to Special:Homepage and make sure an edit suggestion is shown

The HTML tags in the extract in the edit suggestion cards are being interpreted as HTML by the browser:

image.png (349×1 px, 69 KB)

Cause

GrowthExperiments retrieves an extract for the article from the Wikimedia REST API:
https://github.com/wikimedia/mediawiki-extensions-GrowthExperiments/blob/0bc0b3cd13aa4d6b46b051330289809b981e5e15/modules/ext.growthExperiments.DataStore/GrowthTasksApi.js#L298-L299

Later, the extract is inserted as HTML:
https://github.com/wikimedia/mediawiki-extensions-GrowthExperiments/blob/0bc0b3cd13aa4d6b46b051330289809b981e5e15/modules/ext.growthExperiments.Homepage.SuggestedEdits/EditCardWidget.js#L89

However, the "extract" field of the Wikimedia REST API does not return safe HTML (at least based on the fact that the POC works; I couldn't find documentation on the endpoint).
For the article I used as the example, the REST API returns the unescaped HTML tags from the article text:
https://en.wikipedia.org/api/rest_v1/page/summary/Div_and_span

Additional information

  • MediaWiki: 1.45.0-alpha (4589dff)
  • Vector: 9159afd
  • GrowthExperiments: 6806956

Event Timeline

Despite trying various methods for mocking suggested edits linked at https://www.mediawiki.org/wiki/Extension:GrowthExperiments/developer_setup#Suggested_Edits, I was unable to properly set up suggested edits in my development environment (partially due to aspects such as https://addlink-simple.toolforge.org being dead).

Apologies about that. I filled T402720: Update developer instructions for setting Suggested Edits up for us to update the documentation. In the meantime, following "Set up search locally" (and "Link recommendations") will very likely work, but it also requires setting up an ElasticSearch instance locally. Mocking production data should also work (not sure why it requires you to change the JS as well).

Copying & customizing response from the Add Link service (example call) might also work, I'm not 100% sure about the format expectations there.

I used this process to generate an arbitrarily-titled article to Add Link pool (avoiding the manual JS edit hack from the description):

I have no name!@9fdafa6fa954:/var/www/html/w$ # populate Sandbox article with some links to recommend
I have no name!@9fdafa6fa954:/var/www/html/w$ php maintenance/run.php GrowthExperiments:refreshLinkRecommendations --page=Sandbox --verbose --force # to add it to the pool of articles
Refreshing link recommendations...
    checking candidate [0:Sandbox]... success, updating index
I have no name!@9fdafa6fa954:/var/www/html/w$ php maintenance/run.php CirrusSearch:UpdateWeightedTags.php  --tagType classification.prediction.articletopic --tagName 'Geography.Regions.Africa.Africa*' --weight 1000 --page=Sandbox --verbose # to make it easier to find in Special:Homepage

In theory, it should also be possible to trigger this by using the template-based tasks (however, that also requires having CirrusSearch working locally).

Suggested patch:

The patch fixes the issue in question. I also noticed the extract_html endpoint, which seems to provide version that's safe for inclusion in HTML. However, it would also include bold font, etc., and I don't think this would be appropriate to do in the context of the security bug fix.

+2 from a code-review perspective. This is now ready for deployment, which I will take care of on Monday.

Ideally, we would also make this clear in documentation... I found https://github.com/wikimedia/mediawiki-services-mobileapps/blob/master/spec/page/summary.yaml which has some information about individual fields in the endpoint, but https://en.wikipedia.org/api/rest_v1/ does not seem to publish that anywhere :-/.

Urbanecm_WMF moved this task from Incoming to QA on the Growth-Team (Current Sprint) board.

This issue should be now fixed in production.

12:00 <+logmsgbot> !log urbanecm@deploy1003 Started scap sync-world: Deploying a security patch (T402698, T402600)
12:15 <+logmsgbot> !log urbanecm@deploy1003 Finished scap sync-world: Deploying a security patch (T402698, T402600) (duration: 15m 06s)

I used this process to generate an arbitrarily-titled article to Add Link pool (avoiding the manual JS edit hack from the description):

I have no name!@9fdafa6fa954:/var/www/html/w$ # populate Sandbox article with some links to recommend
I have no name!@9fdafa6fa954:/var/www/html/w$ php maintenance/run.php GrowthExperiments:refreshLinkRecommendations --page=Sandbox --verbose --force # to add it to the pool of articles
Refreshing link recommendations...
    checking candidate [0:Sandbox]... success, updating index
I have no name!@9fdafa6fa954:/var/www/html/w$ php maintenance/run.php CirrusSearch:UpdateWeightedTags.php  --tagType classification.prediction.articletopic --tagName 'Geography.Regions.Africa.Africa*' --weight 1000 --page=Sandbox --verbose # to make it easier to find in Special:Homepage

I tried this locally, but I still still couldn't get any tasks to show up... even though refreshLinkRecommendations returned the success message. maybe there is some additional configuration I need?
I think there should just be a simple reproducible guide that lists all steps that are required to get this working after installing the extension on a brand new setup, though T402720 would probably be a better place to discuss this

Given the comment in T402600#11119989, would it be fine to upload this change to Gerrit as well? I don't expect many third parties to be affected in the first place.

Given the comment in T402600#11119989, would it be fine to upload this change to Gerrit as well? I don't expect many third parties to be affected in the first place.

Yes, that's fine.

Change #1184108 had a related patch set uploaded (by Urbanecm; author: SomeRandomDeveloper):

[mediawiki/extensions/GrowthExperiments@master] SECURITY: Insert article extracts as text instead of HTML

https://gerrit.wikimedia.org/r/1184108

Change #1184110 had a related patch set uploaded (by Urbanecm; author: SomeRandomDeveloper):

[mediawiki/extensions/GrowthExperiments@REL1_44] SECURITY: Insert article extracts as text instead of HTML

https://gerrit.wikimedia.org/r/1184110

Change #1184111 had a related patch set uploaded (by Urbanecm; author: SomeRandomDeveloper):

[mediawiki/extensions/GrowthExperiments@REL1_43] SECURITY: Insert article extracts as text instead of HTML

https://gerrit.wikimedia.org/r/1184111

Change #1184114 had a related patch set uploaded (by Urbanecm; author: SomeRandomDeveloper):

[mediawiki/extensions/GrowthExperiments@REL1_39] SECURITY: Insert article extracts as text instead of HTML

https://gerrit.wikimedia.org/r/1184114

Change #1184114 merged by jenkins-bot:

[mediawiki/extensions/GrowthExperiments@REL1_39] SECURITY: Insert article extracts as text instead of HTML

https://gerrit.wikimedia.org/r/1184114

Change #1184110 merged by jenkins-bot:

[mediawiki/extensions/GrowthExperiments@REL1_44] SECURITY: Insert article extracts as text instead of HTML

https://gerrit.wikimedia.org/r/1184110

Change #1184108 merged by jenkins-bot:

[mediawiki/extensions/GrowthExperiments@master] SECURITY: Insert article extracts as text instead of HTML

https://gerrit.wikimedia.org/r/1184108

Change #1184111 merged by jenkins-bot:

[mediawiki/extensions/GrowthExperiments@REL1_43] SECURITY: Insert article extracts as text instead of HTML

https://gerrit.wikimedia.org/r/1184111

Mstyles renamed this task from Stored XSS through article extracts in GrowthExperiments to CVE-2025-62667: Stored XSS through article extracts in GrowthExperiments.Oct 18 2025, 5:07 AM
Mstyles changed the visibility from "Custom Policy" to "Public (No Login Required)".
Mstyles changed the edit policy from "Custom Policy" to "All Users".