Page MenuHomePhabricator

CVE-2025-53483, CVE-2025-53484, CVE-2025-53485: SecurePoll is vulnerable to XSS, CSRF, and lack of authorisation
Closed, ResolvedPublicSecurity

Description

1 - First off, ArchivePage.php and UnarchivePage.php do not check if the request is POSTed or has an edit token, so an evil attacker can convince an election admin to archive or unarchive a page without their intention.

2 - Additionally, if one of the options for a single transferable vote with Droop quota poll is an cross-site scripting payload, such as <script>alert("OOPSIE WOOPSIE!!")</script>, then a voter would get XSSed if they voted for the malicious option. This problem is caused by line 432 of VotePage.php

2025-04-19_16-18.png (991×1 px, 74 KB)

3 - And also, VoterEligibitityPage#executeClear() does not check if the request is POSTed or has a valid edit token, thus also leading to the first problem.

4 - Also SetTwanslationHandler.php doesn't validate that the user is an election admin, so an arbitrary user can change the text even if they're not logged in!
Luckily, this functionality seems to be broken since MediaWiki 1.43, as it cannot properly get the request body and instead replies No valid body.

5 - Lastly, the functions ResultPage::getPagesTab() and ResultPage::getErrorsTab() does not escape user input! So if a malicious user can sneak in a malicious page name, this can happen:

Fortunately, the impact of this problem is reduced due to two things:

  • All but one of the cross-site scripting vulnerable areas are inside elements' contents, which cannot contain the left-angle bracket or the right-angle bracket since it's a title
  • Thus, the one vulnerable area is inside the attribute of an element. However, it depends on SetTranslationHandler.php to work to display, which we have already established doesn't on MediaWiki 1.43.

Question: For some reason, the edit token is checked when voting, but the request is still allowed if it's a CSRF
Instead, it has to validate that the CSRF flag is not unset.


Acceptance Criteria

  • ArchivePage.php and UnarchivePage.php require token (gerrit:1149618)
  • Droop quota poll option escapes input (gerrit:1149655)
  • VoterEligibitityPage#executeClear() requires token (gerrit:1149664)
  • SetTranslationHandler.php validates access rights (gerrit:1149668)
  • ResultPage::getPagesTab() and ResultPage::getErrorsTab() escape user input (gerrit:1149669)

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes

Looks OK, thanks! I have one suggestion on F59511080, but it is non-blocking - feel free to move forward.

Looks OK, thanks! I have one suggestion on F59511080, but it is non-blocking - feel free to move forward.

@Mstyles if this is enough, can we deploy these patches?

Ah I'm sorry I haven't quite made these patches correctly. Let me fix them so they're deployable and post an update when I've done that.

These should now have the appropriate commit message and be ready for deploy.

Reedy added a subscriber: gerritbot.

01-T392341:

02-T392341:

  • Looks fine

03-T392341

  • Same again about the token salts
  • Same again for the error message

04-T392341

  • Docs for SetTranslationHandler::__construct will need updating (or probably remove it) because it's now out of date

05-T392341

  • Looks fine too

  • Updated the message to refer to a session instead of the token (other places also refer to it as a permissions issue but session felt more accurate)
  • I don't think it needs to be a specific salt but maybe someone who knows more has a different opinion? For now I've removed the un/archive salt.

  • Resolved message/salt as above

  • Removed constructor docs

@STran are these patches ready for deployment? I would like to make sure they get out sooner than later.

sbassett changed the task status from Open to In Progress.EditedMay 5 2025, 10:15 PM
sbassett triaged this task as Medium priority.
sbassett subscribed.

Update: I've deployed the first two patches from above:

  1. https://sal.toolforge.org/log/65p0opYB8tZ8Ohr0Y6_s
  2. https://sal.toolforge.org/log/m5qBopYB8tZ8Ohr0v7Q1

All seems stable for now. It would be great if someone with votewiki (or similar) access could confirm these look good within Wikimedia production. Once that has been confirmed, I'm happy to get the last 3 patches deployed this week.

I think votewiki is fairly locked down so @jrbs may be the best person to ask. I have an account there and could probably run these steps myself if someone wants to assign me the rights.

01-T392341

  • Confirm that if you don't pass a token through in the URL, you can't archive an election
  • Confirm that if pass a token through in the URL, you can archive an election

02-T392341

  • Make a new STV poll with one of the options being <script>alert("XSS")</script>
  • Confirm that when you view the ongoing election, an alert doesn't pop up

(and for whenever the other patches go in)

03-T392341

  • Add a voter eligibility list (You can take this action on ended elections)
  • Confirm that if you don't pass a token through in the URL, you can't clear the list
  • Confirm that if pass a token through in the URL, you can clear the list

04-T392341
(This may not be possible to test since I'm not sure we've enabled the config yet)

  • Confirm that you can't use the translate feature if you're not an election admin

05-T392341
(This may not be possible to test since I'm not sure we've enabled the config yet)

  • Create a page, foo/ style='animation: oo-ui-pendingElement-stripes' onanimationstart='location="duckduckgo.com"'
  • From the /translate page of a poll, try to use the "Import translations" feature and enter 'foo' as the URL and submit
  • Confirm that the list of pages pulled contains the payload page but that you are not redirected

I think votewiki is fairly locked down so @jrbs may be the best person to ask. I have an account there and could probably run these steps myself if someone wants to assign me the rights.

01-T392341

  • Confirm that if you don't pass a token through in the URL, you can't archive an election
  • Confirm that if pass a token through in the URL, you can archive an election

02-T392341

  • Make a new STV poll with one of the options being <script>alert("XSS")</script>
  • Confirm that when you view the ongoing election, an alert doesn't pop up

(and for whenever the other patches go in)

03-T392341

  • Add a voter eligibility list (You can take this action on ended elections)
  • Confirm that if you don't pass a token through in the URL, you can't clear the list
  • Confirm that if pass a token through in the URL, you can clear the list

04-T392341
(This may not be possible to test since I'm not sure we've enabled the config yet)

  • Confirm that you can't use the translate feature if you're not an election admin

05-T392341
(This may not be possible to test since I'm not sure we've enabled the config yet)

  • Create a page, foo/ style='animation: oo-ui-pendingElement-stripes' onanimationstart='location="duckduckgo.com"'
  • From the /translate page of a poll, try to use the "Import translations" feature and enter 'foo' as the URL and submit
  • Confirm that the list of pages pulled contains the payload page but that you are not redirected

Thanks for compiling this and sorry for my delay in responding! I have provided you the relevant rights on votewiki if you want to test these yourself in production.

@STran - per @jrbs' rights-granting above, would you be available to help test the rest of the security patches during next Monday's security deployment window?

I've run through the QA steps as stated above:

01-T392341

  • Confirmed you need a valid token to archive an election
  • Confirmed you need a valid token to unarchive an election

02-T392341
I was trying to test this as it seems like Securepoll is currently broken. I've just filed T393790: SecurePoll can no longer add questions to new polls.

Is it possible to deploy 03-T392341 for QA independently of 04-T392341 and 05-T392341? 04/05 depend on a configuration option that I'm not sure has been enabled on production servers yet. I'm wondering if we could take some of this through the non-security flow and fix it as part of enabling the feature? Or should we enable the feature first, confirm it's broken, and fix it as part of the security workflow?

@sbassett oh you also just posted. Yes I can be available at that time but only 01-T392341 and 03-T392341 are testable as 02/04/05 all rely on features that are currently broken.

@sbassett oh you also just posted. Yes I can be available at that time but only 01-T392341 and 03-T392341 are testable as 02/04/05 all rely on features that are currently broken.

Ok, sounds good. 01 and 02 are already deployed, so I suppose you could test those whenever, now that you have votewiki perms. We can deploy 03 during this coming Monday's security deployment window and test at that time. And we can do whatever we need to, in order to accommodate 04 and 05, if those are dependent upon a config patch or whatever.

@sbassett I've already tested 01 and confirmed it's behaving as expected. I can't test 02 until the fix for for T393790 is in (this can be backported if necessary, I'm doublechecking now). 03 can be tested when it's deployed in the next security deployment window. As for 04 and 05. I think we have 2 options:

  1. Deploy config, then 04/05. We need to set $wgSecurePollTranslationImportSourceUrl to https://meta.wikimedia.org/w/api.php which @jrbs has mentioned is where translations for elections happen. I've looked and confirmed that there are translations we can test against (examples). This has the benefit of allowing no lapse in vulnerability availability and the fix, as the API fix and the permission check are bundled together in 04. We'd roll back the config change when Ibdbe436331dbac847cf5a224baee8eb3bc6e9bb4 goes out.
  1. Work around Ibdbe436331dbac847cf5a224baee8eb3bc6e9bb4. This work was done to resolve T387720: Prefer a parameter over a configuration for importing translations in SecurePoll and I think can be merged sooner rather than later. I think ideally 04 would go in first, which is the permission check and incidentally fixes the API call, then this patch which makes it easier to test the feature. However, this seems like it could cause us a few headaches between managing versions, rebases, conflicts, etc.

I backported T393790 this morning, tested 02, and confirmed it worked as expected. Next steps for 03, 04, and 05 are outlined as above.

I backported T393790 this morning, tested 02, and confirmed it worked as expected. Next steps for 03, 04, and 05 are outlined as above.

Ok, thanks for the backporting and testing for 02. I'll plan to deploy patch 03 today and let you test when you can.

And then it sounds like we should work to get Ibdbe43633 merged so we can deploy and easily test 04 and 05?

After coordinating with @STran, I've deployed patches 03, 04 and 05 (SAL). Error rates seem fine. @STran will now test patch 03 and once Ibdbe43633 is merged and rolls out with wmf.29 this week, they will be able to test and confirm patches 04 and 05 (which are basically just noops in production for the time being).

Tested 03 on votewiki and confirmed that the voter eligibility clear list link now passes along a token and that token is required to perform the action.

Thanks for everyone's work on this. Sounds like 1-3 are done and we are waiting on 4-5. Are 4-5 blockers for T378287: Enable SecurePoll extension and electionclerk user group on enwiki, or are those "minor" enough that T378287 can proceed?

I'd like to wait for 4 and 5 as an unprotected open translation interface seems kind of bad, doubly so since afaik we don't log changes to translations. The fix should roll out with an update that re-enables the feature (feature is on the main branch, security patches are being merged in as necessary) with this train, assuming no train blockers.

We'll need to update patch #4 due to T394900.

In addition to the updated 04 patch, QA needs to wait on I1b4fbcabbca7cc5475c7bbd429cb8ab068bc4ee3 to be backported, which I've scheduled for the upcoming window.

Backported but now blocked on the php fatal error

New 04 patch

Updated patch is now deployed to 1.45-wmf.2.

Confirmed that:

04

  • I cannot access the translation endpoint of an election I'm not an admin for

05

  • A translation page with an XSS payload is not triggered when I attempt to import it via the import dialog

Change #1149618 had a related patch set uploaded (by STran; author: STran):

[mediawiki/extensions/SecurePoll@master] SECURITY: Require an edit token to archive/unarchive elections

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

Change #1149655 had a related patch set uploaded (by STran; author: STran):

[mediawiki/extensions/SecurePoll@master] SECURITY: Sanitize displayed STV option text

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

Change #1149664 had a related patch set uploaded (by STran; author: STran):

[mediawiki/extensions/SecurePoll@master] SECURITY: Require an edit token to clear voter eligibility lists

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

Change #1149668 had a related patch set uploaded (by STran; author: STran):

[mediawiki/extensions/SecurePoll@master] SECURITY: Gate access to SetTranslationHandler

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

Change #1149669 had a related patch set uploaded (by STran; author: STran):

[mediawiki/extensions/SecurePoll@master] SECURITY: Escape links generated by the translation import results tab

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

Change #1149655 merged by jenkins-bot:

[mediawiki/extensions/SecurePoll@master] SECURITY: Sanitize displayed STV option text

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

Change #1149618 merged by jenkins-bot:

[mediawiki/extensions/SecurePoll@master] SECURITY: Require an edit token to archive/unarchive elections

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

Change #1149668 merged by jenkins-bot:

[mediawiki/extensions/SecurePoll@master] SECURITY: Gate access to SetTranslationHandler

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

Change #1149664 merged by jenkins-bot:

[mediawiki/extensions/SecurePoll@master] SECURITY: Require an edit token to clear voter eligibility lists

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

SecurityPatchBot changed the task status from In Progress to Open.May 23 2025, 11:52 PM
SecurityPatchBot raised the priority of this task from Medium to Unbreak Now!.

Patch 01-T392341.patch is currently failing to apply for the most recent code in the mainline branch of extensions/SecurePoll. This is blocking MediaWiki release 1.45.0-wmf.3(T392173)

If the patch needs to be rebased

To unblock the release, a new version of the patch can be placed at the right location in the deployment server with the following Scap command:

REVISED_PATCH=<path_to_revised_patch>
scap update-patch --message-body 'Rebase to solve merge conflicts with mainline code' /srv/patches/1.45.0-wmf.3/extensions/SecurePoll/01-T392341.patch "$REVISED_PATCH"

If the patch has been made public

To unblock the release, the patch can be removed for the right version from the deployment server with the following Scap command:

scap remove-patch --message-body 'Remove patch already made public' /srv/patches/1.45.0-wmf.3/extensions/SecurePoll/01-T392341.patch

(Note that if patches for the version don't exist yet, they will be created and the patch you specified removed)

sbassett changed the task status from Open to In Progress.May 24 2025, 12:43 AM
sbassett lowered the priority of this task from Unbreak Now! to Medium.

Ran scap remove-patch for the first 4 patches, which were merged in gerrit: https://sal.toolforge.org/log/bx7M_5YBffdvpiTrqZR4

Change #1149669 merged by jenkins-bot:

[mediawiki/extensions/SecurePoll@master] SECURITY: Escape links generated by the translation import results tab

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

Change #1149669 merged by jenkins-bot:

[mediawiki/extensions/SecurePoll@master] SECURITY: Escape links generated by the translation import results tab

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

So this should now get cut for 1.45.0-wmf.4 next week, and we'll be able to remove it from deployment. Maybe I can do that on Thursday or Friday before @SecurityPatchBot sets this as a UBN over the weekend :)

It looks like the last remaining security patches will ride the train on Thursday. Is there a manual testing step after these ride the train, or can we close this ticket on Thursday? Also, will T378287: Enable SecurePoll extension and electionclerk user group on enwiki become unblocked on Thursday?

It looks like the last remaining security tickets will ride the train on Thursday.

Correct.

Is there a manual testing step after these ride the train, or can we close this ticket on Thursday?

There shouldn't need to be as the patches were tested by @STran when we deployed them initially (04 and 05 mentioned in T392341#10844541)

Also, will T378287: Enable SecurePoll extension and electionclerk user group on enwiki become unblocked on Thursday?

It should, yes, if this was the only task blocking it.

Change #1165927 had a related patch set uploaded (by Mmartorana; author: STran):

[mediawiki/extensions/SecurePoll@REL1_44] SECURITY: Require an edit token to archive/unarchive elections

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

Change #1165927 merged by jenkins-bot:

[mediawiki/extensions/SecurePoll@REL1_44] SECURITY: Require an edit token to archive/unarchive elections

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

Change #1166900 had a related patch set uploaded (by Dreamy Jazz; author: STran):

[mediawiki/extensions/SecurePoll@REL1_44] SECURITY: Require an edit token to clear voter eligibility lists

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

Change #1166900 merged by jenkins-bot:

[mediawiki/extensions/SecurePoll@REL1_44] SECURITY: Require an edit token to clear voter eligibility lists

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

mmartorana renamed this task from SecurePoll is vulnerable to XSS, CSRF, and lack of authorisation to CVE-2025-53484: SecurePoll is vulnerable to XSS, CSRF, and lack of authorisation.Tue, Jul 8, 5:41 PM
mmartorana closed this task as Resolved.
mmartorana changed the visibility from "Custom Policy" to "Public (No Login Required)".
mmartorana renamed this task from CVE-2025-53484: SecurePoll is vulnerable to XSS, CSRF, and lack of authorisation to CVE-2025-53483, CVE-2025-53484, CVE-2025-53485: SecurePoll is vulnerable to XSS, CSRF, and lack of authorisation.Tue, Jul 8, 5:44 PM