From 96060ac5d5cbe3dc1480ba4b60244792afd7a2d5 Mon Sep 17 00:00:00 2001
From: SomeRandomDeveloper <thisisnotmyname275@gmail.com>
Date: Sun, 7 Sep 2025 22:29:31 +0200
Subject: [PATCH] SECURITY: Fix several stored i18n XSS vulnerabilities

Escape or parse system messages in JS before inserting them as HTML.

Bug: T403923
Change-Id: If235d6e6c1d37de6748ef4774cdb3438f52ac532
---
 extension.json       |  1 +
 i18n/en.json         |  2 +-
 resources/js/Poll.js | 10 +++++-----
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/extension.json b/extension.json
index 0dd7ca1..71c43ce 100644
--- a/extension.json
+++ b/extension.json
@@ -99,6 +99,7 @@
 			],
 			"dependencies": [
 				"mediawiki.api",
+				"mediawiki.jqueryMsg",
 				"mediawiki.util",
 				"ext.socialprofile.LightBox",
 				"oojs-ui-core",
diff --git a/i18n/en.json b/i18n/en.json
index 6097b6a..b73f655 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -52,7 +52,7 @@
 	"poll-edit-title": "Editing poll - $1",
 	"poll-embed": "Embed on wiki page",
 	"poll-enterquestion": "You must enter a question.",
-	"poll-finished": "<b>There are no more polls left. Add your <a href=\"$1\">own!</a></b> Or <a href=\"$2\">view results of this poll</a>.",
+	"poll-finished": "<b>There are no more polls left. Add your [$1 own!]</b> Or [$2 view results of this poll].",
 	"poll-flagged": "This poll has been flagged",
 	"poll-flagged-message": "Are you sure you want to flag this poll?",
 	"poll-flag-poll": "Flag poll",
diff --git a/resources/js/Poll.js b/resources/js/Poll.js
index 8e8d716..81e4036 100644
--- a/resources/js/Poll.js
+++ b/resources/js/Poll.js
@@ -50,7 +50,7 @@ var PollNY = {
 				'<img src="' + mw.config.get( 'wgExtensionAssetsPath' ) + '/SocialProfile/images/ajax-loader-white.gif" alt="" />'
 			);
 		} else {
-			window.LightBox.setText( mw.msg( 'poll-js-loading' ) );
+			window.LightBox.setText( mw.message( 'poll-js-loading' ).escaped() );
 		}
 	},
 
@@ -132,11 +132,11 @@ var PollNY = {
 				} else {
 					// We have run out of polls to show
 					// Show a lightbox prompting the user to create more polls
-					window.LightBox.setText( mw.msg(
+					window.LightBox.setText( mw.message(
 						'poll-finished',
 						mw.util.getUrl( mw.config.get( 'wgFormattedNamespaces' )[ -1 ] + ':' + 'CreatePoll' ),
 						window.location
-					) );
+					).parse() );
 				}
 			}
 		} );
@@ -273,7 +273,7 @@ var PollNY = {
 					pollID: id,
 					status: status
 				} ).done( function () {
-					jQuery( '#poll-' + id + '-controls' ).html( mw.msg( 'poll-js-action-complete' ) );
+					jQuery( '#poll-' + id + '-controls' ).text( mw.msg( 'poll-js-action-complete' ) );
 				} );
 			}
 		} );
@@ -295,7 +295,7 @@ var PollNY = {
 					what: 'delete',
 					pollID: id
 				} ).done( function () {
-					jQuery( '#poll-' + id + '-controls' ).html( mw.msg( 'poll-js-action-complete' ) );
+					jQuery( '#poll-' + id + '-controls' ).text( mw.msg( 'poll-js-action-complete' ) );
 				} );
 			}
 		} );
-- 
2.51.0

