Page MenuHomePhabricator

CVE-2025-6595: Stored XSS through system messages in MultimediaViewer
Closed, ResolvedPublic3 Estimated Story PointsSecurity

Description

Multiple system messages in MultimediaViewer are vulnerable to stored XSS.

multimediaviewer-multiple-authors-combine

Cause: https://gerrit.wikimedia.org/g/mediawiki/extensions/MultimediaViewer/+/8423935d2167119bc3421a946c720138456cb6b4/resources/mmv/ui/mmv.ui.metadataPanel.js#467

multimediaviewer-repository-local

  1. Upload a file to your wiki
  2. Add the file to a page
  3. Go to the page using the ?uselang=x-xss parameter
  4. Click on the thumbnail to open it in MultimediaViewer

image.png (173×407 px, 10 KB)

Cause: https://gerrit.wikimedia.org/g/mediawiki/extensions/MultimediaViewer/+/8423935d2167119bc3421a946c720138456cb6b4/resources/mmv/ui/mmv.ui.stripeButtons.js#78

multimediaviewer-view-expanded

  1. Upload a file to your wiki
  2. Go to the file's page while using the ?uselang=x-xss parameter
  3. Click on the thumbnail to open it in MultimediaViewer

image.png (139×402 px, 7 KB)

Cause: https://gerrit.wikimedia.org/g/mediawiki/extensions/MultimediaViewer/+/8423935d2167119bc3421a946c720138456cb6b4/resources/mmv.bootstrap/mmv.bootstrap.js#391

multimediaviewer-copy-button

  1. Upload a file to your wiki
  2. Add the file to a page
  3. Go to the page using the ?uselang=x-xss parameter
  4. Click on the thumbnail to open it in MultimediaViewer
  5. Click the Download button in the bottom right

image.png (160×371 px, 9 KB)

Cause: https://gerrit.wikimedia.org/g/mediawiki/extensions/MultimediaViewer/+/8423935d2167119bc3421a946c720138456cb6b4/resources/mmv.ui.reuse/mmv.ui.utils.js#53

multimediaviewer-download

  1. Upload a file to your wiki
  2. Add the file to a page
  3. Go to the page using the ?uselang=x-xss parameter
  4. Click on the thumbnail to open it in MultimediaViewer
  5. Click the Download button in the bottom right

image.png (126×378 px, 5 KB)

Cause: Concatenation of HTML and the unescaped message at https://github.com/wikimedia/mediawiki-extensions-MultimediaViewer/blob/8423935d2167119bc3421a946c720138456cb6b4/resources/mmv.ui.reuse/mmv.ui.download.pane.js#L83

multimediaviewer-download-preview-link-title

image.png (160×372 px, 10 KB)

Cause: Calling .html() with the unescaped message as the argument: https://github.com/wikimedia/mediawiki-extensions-MultimediaViewer/blob/8423935d2167119bc3421a946c720138456cb6b4/resources/mmv.ui.reuse/mmv.ui.download.pane.js#L108

Requirement

Fix multiple stored XSS vulnerabilities in MultimediaViewer by ensuring system messages are properly escaped and not directly injected into the DOM using .html() or string concatenation.

Vulnerable messages:

  • multimediaviewer-multiple-authors-combine
  • multimediaviewer-repository-local
  • multimediaviewer-view-expanded
  • multimediaviewer-copy-button
  • multimediaviewer-download
  • multimediaviewer-download-preview-link-title

All are exploitable by manipulating the uselang parameter to x-xss, which injects arbitrary content into localized UI elements in MultimediaViewer.

BDD

Feature: XSS protection in MultimediaViewer

Scenario: Localized system messages are properly escaped
Given a file is uploaded and added to a wiki page
And the URL is accessed with ?uselang=x-xss
When the thumbnail is clicked to open MultimediaViewer
Then no XSS is executed in the following UI elements:
| Message key                                       |
| multimediaviewer-multiple-authors-combine        |
| multimediaviewer-repository-local                |
| multimediaviewer-view-expanded                   |
| multimediaviewer-copy-button                     |
| multimediaviewer-download                        |
| multimediaviewer-download-preview-link-title     |

Test Steps

Test Case 1: Validate XSS is not triggered in multimediaviewer-multiple-authors-combine

  1. Upload a file to the wiki
  2. Add the file to a wiki page
  3. Visit the page with ?uselang=x-xss
  4. Click the thumbnail to open MultimediaViewer
  5. AC1: Confirm the multiple authors label is shown without script execution

Test Case 2: Validate XSS is not triggered in multimediaviewer-repository-local

  1. Repeat steps from Test Case 1
  2. AC2: Confirm repository name in MultimediaViewer is not executable HTML

Test Case 3: Validate XSS is not triggered in multimediaviewer-view-expanded

  1. Visit the file’s page directly (not via a content page)
  2. Add ?uselang=x-xss to the URL
  3. Click the file to open in MultimediaViewer
  4. AC3: Confirm view-expanded label is escaped

Test Case 4: Validate XSS is not triggered in multimediaviewer-copy-button

  1. Open any file with ?uselang=x-xss
  2. Open MultimediaViewer and click “Download”
  3. AC4: Confirm Copy button text is safe

Test Case 5: Validate XSS is not triggered in multimediaviewer-download

  1. Open MultimediaViewer with ?uselang=x-xss
  2. Click “Download”
  3. AC5: Confirm Download label is not executing HTML

Test Case 6: Validate XSS is not triggered in multimediaviewer-download-preview-link-title

  1. Open MultimediaViewer and click “Download” tab
  2. AC6: Confirm preview link title is escaped properly

QA Results - Prod

Related Objects

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
SomeRandomDeveloper removed a parent task: Restricted Task.
SomeRandomDeveloper added a parent task: Restricted Task.

@sbassett do we have an assessment of how urgent this is? Both for prioritization and figuring out how quickly we can remedy it

@sbassett do we have an assessment of how urgent this is? Both for prioritization and figuring out how quickly we can remedy it

It's low risk but something we should definitely fix. If someone has a patch, it can get posted here for review, so that we can privately deploy it to production.

sbassett changed Author Affiliation from N/A to Wikimedia Communities.May 30 2025, 8:00 PM
sbassett changed Risk Rating from N/A to Low.
SToyofuku-WMF moved this task from Incoming to Q4 on the Web-Team board.

Sounds good, thank you! I'll discuss with our engineers about how long we think it would take us to get a patch together. I'll also tag our product manager in Slack to let her know that this has come up and get her input on when we should start work on it. My sense is likely this will be picked up in our upcoming sprint (beginning Wednesday the 4th), but I'll let her be the judge of that

@ovasileva I triaged as high given it's a security vuln, but feel free to set the priority lower, especially given the above

Jdlrobson-WMF set the point value for this task to 3.Jun 2 2025, 5:41 PM
Jdlrobson-WMF moved this task from Q4 to Sprint Backlog on the Web-Team board.

These issues looks pretty straight-forward to fix. Either just s/append/text/ or s/mw.msg(...)/mw.message(...).escaped()/ for the affected lines.

I'm pretty sure mw.msg( '...' ) returns a string, so you can't use .escaped() on it. This change breaks MMV for me. You have to use mw.message( '...' ).escaped() instead, see also the messages documentation: https://www.mediawiki.org/wiki/Manual:Messages_API#Format_options

image.png (67×367 px, 10 KB)

Sorry @SomeRandomDeveloper. See here

This one works fine for me.
Minor suggestion for improvement, .text() could be used here instead of adding the escaped message as HTML:

diff --git a/resources/mmv.ui.reuse/mmv.ui.download.pane.js b/resources/mmv.ui.reuse/mmv.ui.download.pane.js
index 51b2cbfd..cb098935 100644
--- a/resources/mmv.ui.reuse/mmv.ui.download.pane.js
+++ b/resources/mmv.ui.reuse/mmv.ui.download.pane.js
@@ -105,7 +105,7 @@ class DownloadPane extends UiElement {
                this.$previewLink = $( '<a>' )
                        .attr( 'target', '_blank' )
                        .addClass( 'cdx-docs-link' )
-                       .html( mw.message( 'multimediaviewer-download-preview-link-title' ).escaped() )
+                       .text( mw.msg( 'multimediaviewer-download-preview-link-title' ) )
                        .appendTo( $container );
        }

@SomeRandomDeveloper Thanks. Just to confirm: should this patch for review only fix the mw.msg() usage in mmv.ui.download.pane.js, or should I update similar patterns in the other mentioned files too?

Patch LGTM (with or without @SomeRandomDeveloper 's modification). Personally I prefer being explicit and using escaped.

@sbassett would you be able to arrange the merge and deploy to Gerrit ? (I am going to be out from tomorrow)

@sbassett would you be able to arrange the merge and deploy to Gerrit ? (I am going to be out from tomorrow)

Yes. We'd likely want to discretely deploy this as a security patch to Wikimedia production. And then it would be released with the next core security release, since it's a bundled extension.

sbassett added a parent task: Restricted Task.Jun 10 2025, 9:36 PM
sbassett moved this task from Watching to Security Patch To Deploy on the Security-Team board.

Updated patch taking into account @SomeRandomDeveloper's suggestion above in T394863#10901988

-                       .html( mw.message( 'multimediaviewer-download-preview-link-title' ).escaped() )
+                       .text( mw.msg( 'multimediaviewer-download-preview-link-title' ) )

(only in resources/mmv.ui.reuse/mmv.ui.download.pane.js):

...which @Mstyles should be deploying to production shortly.

sbassett changed the task status from Open to In Progress.Jun 12 2025, 10:07 PM
sbassett moved this task from Security Patch To Deploy to Watching on the Security-Team board.
Edtadros subscribed.

Test Result - Prod

Status: ✅ PASS
Environment: testwiki
OS: macOS Sequoia 15.5
Browser: Chrome Canary (latest as of test date)
Device: MS
Emulated Device: NA

Test Steps

Test Case 1: Validate XSS is not triggered in multimediaviewer-multiple-authors-combine

  1. Upload a file to the wiki
  2. Add the file to a wiki page
  3. Visit the page with ?uselang=x-xss
  4. Click the thumbnail to open MultimediaViewer
  5. AC1: Confirm the multiple authors label is shown without script execution

see below
Test Case 2: Validate XSS is not triggered in multimediaviewer-repository-local

  1. Repeat steps from Test Case 1
  2. AC2: Confirm repository name in MultimediaViewer is not executable HTML

see below
Test Case 3: Validate XSS is not triggered in multimediaviewer-view-expanded

  1. Visit the file’s page directly (not via a content page)
  2. Add ?uselang=x-xss to the URL
  3. Click the file to open in MultimediaViewer
  4. AC3: Confirm view-expanded label is escaped

see below
Test Case 4: Validate XSS is not triggered in multimediaviewer-copy-button

  1. Open any file with ?uselang=x-xss
  2. Open MultimediaViewer and click “Download”
  3. AC4: Confirm Copy button text is safe

see below
Test Case 5: Validate XSS is not triggered in multimediaviewer-download

  1. Open MultimediaViewer with ?uselang=x-xss
  2. Click “Download”
  3. AC5: Confirm Download label is not executing HTML

see below
Test Case 6: Validate XSS is not triggered in multimediaviewer-download-preview-link-title

  1. Open MultimediaViewer and click “Download” tab
  2. AC6: Confirm preview link title is escaped properly

see below

I'm not entirely sure what I"m looking for here, but I didn't see any dialogs, or console messages that that were outside of normal behavior.

screenshot 2.mov.gif (846×1 px, 510 KB)

screenshot 1.mov.gif (846×1 px, 717 KB)

Afaik $wgUseXssLanguage is disabled on all (public) WMF wikis, so this can't be tested easily without spinning up a local MW instance. If it was enabled, all messages on the screen (at least those that don't use inContentLanguage) would appear as <script>alert('message-key')</script>"><script>alert('message-key')</script><x y="()

Reedy subscribed.

rEMMVa8a5247c5e8f: Use mw.msg shortcut seems to be related on numerous of the changes being fixed here... That's only in REL1_43 and REL1_44.

It looks like the patch therefore only partially applies to REL1_42/REL1_39 -- mmv.ui.download.pane.js and mmv.ui.utils.js don't apply.

Reedy renamed this task from Stored XSS through system messages in MultimediaViewer to CVE-2025-6595: Stored XSS through system messages in MultimediaViewer.Jun 24 2025, 11:27 PM

Change #1165080 had a related patch set uploaded (by Reedy; author: Reedy):

[mediawiki/core@REL1_43] T394863

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

Change #1165089 had a related patch set uploaded (by Reedy; author: Reedy):

[mediawiki/core@REL1_39] T394863

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

Change #1165106 had a related patch set uploaded (by Reedy; author: Kimberly Sarabia):

[mediawiki/extensions/MultimediaViewer@master] SECURITY: Fix unescaped mw.msg usage

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

Change #1165106 merged by jenkins-bot:

[mediawiki/extensions/MultimediaViewer@master] SECURITY: Fix unescaped mw.msg usage

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

Change #1165089 abandoned by Reedy:

[mediawiki/core@REL1_39] T394863

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

Change #1165080 abandoned by Reedy:

[mediawiki/core@REL1_43] T394863

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

Change #1165128 had a related patch set uploaded (by Reedy; author: Kimberly Sarabia):

[mediawiki/extensions/MultimediaViewer@REL1_44] SECURITY: Fix unescaped mw.msg usage

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

Change #1165129 had a related patch set uploaded (by Reedy; author: Kimberly Sarabia):

[mediawiki/extensions/MultimediaViewer@REL1_43] SECURITY: Fix unescaped mw.msg usage

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

Change #1165130 had a related patch set uploaded (by Reedy; author: Kimberly Sarabia):

[mediawiki/extensions/MultimediaViewer@REL1_42] SECURITY: Fix unescaped mw.msg usage

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

Change #1165140 had a related patch set uploaded (by Reedy; author: Reedy):

[mediawiki/core@REL1_42] T394863

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

Change #1165140 abandoned by Reedy:

[mediawiki/core@REL1_42] T394863

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

Change #1165144 had a related patch set uploaded (by Reedy; author: Kimberly Sarabia):

[mediawiki/extensions/MultimediaViewer@REL1_39] SECURITY: Fix unescaped mw.msg usage

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

Change #1165128 merged by jenkins-bot:

[mediawiki/extensions/MultimediaViewer@REL1_44] SECURITY: Fix unescaped mw.msg usage

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

Change #1165144 merged by jenkins-bot:

[mediawiki/extensions/MultimediaViewer@REL1_39] SECURITY: Fix unescaped mw.msg usage

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

Change #1165130 merged by jenkins-bot:

[mediawiki/extensions/MultimediaViewer@REL1_42] SECURITY: Fix unescaped mw.msg usage

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

Change #1165129 merged by jenkins-bot:

[mediawiki/extensions/MultimediaViewer@REL1_43] SECURITY: Fix unescaped mw.msg usage

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

sbassett changed the visibility from "Custom Policy" to "Public (No Login Required)".
sbassett changed the edit policy from "Custom Policy" to "All Users".