The non-jqueryMsg version of mw.message( … ).parse() doesn't escape HTML. This affects both message contents (which are generally safe) and the parameters (which can be based on user input). (When jqueryMsg *is* loaded, it correctly accepts only whitelisted tags in message contents, and escapes all parameters.)
There are two cases when it's used:
- When the mediawiki.jqueryMsg ResourceLoader module is not loaded. This is unlikely to be an issue in practice because:
- Tons of things load jqueryMsg these days, it's probably included on almost all pages on any serious wiki. I managed to reproduce the issue on Special:SpecialPages on a wiki with no extensions installed.
- Calling .parse() only makes sense if you have loaded jqueryMsg, so unless other modules have missing dependencies, this never happens.
- When jqueryMsg thinks the message is "simple" and falls back to the basic version to avoid expensive parsing. This is done for messages that do not contain {{, [, <, >, &.
- Since that check ensures that these messages don't contain HTML themselves, this leaves the problem of unescaped parameters.
// This message contains '<', so it will always go through jqueryMsg if it's loaded mw.messages.set( 'foo1', '<img onerror="alert()" src="foo">' ); $( 'body' ).append( mw.message( 'foo1' ).parse() ); // This message also contains '<', so it will always go through jqueryMsg if it's loaded mw.messages.set( 'foo2', '<b>$1</b>' ); $( 'body' ).append( mw.message( 'foo2', '<img onerror="alert()" src="foo">' ).parse() ); // This message will never go through jqueryMsg mw.messages.set( 'foo3', '$1' ); $( 'body' ).append( mw.message( 'foo3', '<img onerror="alert()" src="foo">' ).parse() );
The non-jqueryMsg implementation of .parse() should probably escape the output. Basically, it should be equivalent to .escaped() and not .text(). (Take care not to accidentally double-escape in the jqueryMsg case.)